summaryrefslogtreecommitdiffstats
path: root/src/plugins/directshow/camera/dscamerasession.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/directshow/camera/dscamerasession.cpp')
-rw-r--r--src/plugins/directshow/camera/dscamerasession.cpp1177
1 files changed, 0 insertions, 1177 deletions
diff --git a/src/plugins/directshow/camera/dscamerasession.cpp b/src/plugins/directshow/camera/dscamerasession.cpp
deleted file mode 100644
index 7ceefe2c5..000000000
--- a/src/plugins/directshow/camera/dscamerasession.cpp
+++ /dev/null
@@ -1,1177 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtCore/qdebug.h>
-#include <QFile>
-#include <QtConcurrent/QtConcurrentRun>
-#include <QtMultimedia/qabstractvideobuffer.h>
-#include <QtMultimedia/qvideosurfaceformat.h>
-#include <QtMultimedia/qcameraimagecapture.h>
-#include <private/qmemoryvideobuffer_p.h>
-
-#include "dscamerasession.h"
-#include "dsvideorenderer.h"
-#include "directshowsamplegrabber.h"
-#include "directshowcameraglobal.h"
-#include "directshowmediatype.h"
-#include "directshowutils.h"
-#include "directshowvideoprobecontrol.h"
-
-QT_BEGIN_NAMESPACE
-
-DSCameraSession::DSCameraSession(QObject *parent)
- : QObject(parent)
-{
- connect(this, &DSCameraSession::statusChanged,
- this, &DSCameraSession::updateReadyForCapture);
-
- m_deviceLostEventTimer.setSingleShot(true);
- connect(&m_deviceLostEventTimer, &QTimer::timeout, [&]() {
- IMediaEvent *pEvent = com_cast<IMediaEvent>(m_filterGraph, IID_IMediaEvent);
- if (!pEvent)
- return;
-
- long eventCode;
- LONG_PTR param1;
- LONG_PTR param2;
- while (pEvent->GetEvent(&eventCode, &param1, &param2, 0) == S_OK) {
- switch (eventCode) {
- case EC_DEVICE_LOST:
- unload();
- break;
- default:
- break;
- }
-
- pEvent->FreeEventParams(eventCode, param1, param2);
- }
-
- pEvent->Release();
- });
-}
-
-DSCameraSession::~DSCameraSession()
-{
- unload();
-}
-
-void DSCameraSession::setSurface(QAbstractVideoSurface* surface)
-{
- m_surface = surface;
-}
-
-void DSCameraSession::setDevice(const QString &device)
-{
- m_sourceDeviceName = device;
-}
-
-QCameraViewfinderSettings DSCameraSession::viewfinderSettings() const
-{
- return m_status == QCamera::ActiveStatus ? m_actualViewfinderSettings : m_viewfinderSettings;
-}
-
-void DSCameraSession::setViewfinderSettings(const QCameraViewfinderSettings &settings)
-{
- m_viewfinderSettings = settings;
-}
-
-qreal DSCameraSession::scaledImageProcessingParameterValue(
- const ImageProcessingParameterInfo &sourceValueInfo)
-{
- if (sourceValueInfo.currentValue == sourceValueInfo.defaultValue)
- return 0.0f;
- if (sourceValueInfo.currentValue < sourceValueInfo.defaultValue) {
- return ((sourceValueInfo.currentValue - sourceValueInfo.minimumValue)
- / qreal(sourceValueInfo.defaultValue - sourceValueInfo.minimumValue))
- + (-1.0f);
- }
- return ((sourceValueInfo.currentValue - sourceValueInfo.defaultValue)
- / qreal(sourceValueInfo.maximumValue - sourceValueInfo.defaultValue));
-}
-
-qint32 DSCameraSession::sourceImageProcessingParameterValue(
- qreal scaledValue, const ImageProcessingParameterInfo &valueRange)
-{
- if (qFuzzyIsNull(scaledValue))
- return valueRange.defaultValue;
- if (scaledValue < 0.0f) {
- return ((scaledValue - (-1.0f)) * (valueRange.defaultValue - valueRange.minimumValue))
- + valueRange.minimumValue;
- }
- return (scaledValue * (valueRange.maximumValue - valueRange.defaultValue))
- + valueRange.defaultValue;
-}
-
-static QCameraImageProcessingControl::ProcessingParameter searchRelatedResultingParameter(
- QCameraImageProcessingControl::ProcessingParameter sourceParameter)
-{
- if (sourceParameter == QCameraImageProcessingControl::WhiteBalancePreset)
- return QCameraImageProcessingControl::ColorTemperature;
- return sourceParameter;
-}
-
-bool DSCameraSession::isImageProcessingParameterSupported(
- QCameraImageProcessingControl::ProcessingParameter parameter) const
-{
- const QCameraImageProcessingControl::ProcessingParameter resultingParameter =
- searchRelatedResultingParameter(parameter);
-
- return m_imageProcessingParametersInfos.contains(resultingParameter);
-}
-
-bool DSCameraSession::isImageProcessingParameterValueSupported(
- QCameraImageProcessingControl::ProcessingParameter parameter,
- const QVariant &value) const
-{
- const QCameraImageProcessingControl::ProcessingParameter resultingParameter =
- searchRelatedResultingParameter(parameter);
-
- QMap<QCameraImageProcessingControl::ProcessingParameter,
- ImageProcessingParameterInfo>::const_iterator sourceValueInfo =
- m_imageProcessingParametersInfos.constFind(resultingParameter);
-
- if (sourceValueInfo == m_imageProcessingParametersInfos.constEnd())
- return false;
-
- switch (parameter) {
-
- case QCameraImageProcessingControl::WhiteBalancePreset: {
- const QCameraImageProcessing::WhiteBalanceMode checkedValue =
- value.value<QCameraImageProcessing::WhiteBalanceMode>();
- // Supports only the Manual and the Auto values
- if (checkedValue != QCameraImageProcessing::WhiteBalanceManual
- && checkedValue != QCameraImageProcessing::WhiteBalanceAuto) {
- return false;
- }
- }
- break;
-
- case QCameraImageProcessingControl::ColorTemperature: {
- const qint32 checkedValue = value.toInt();
- if (checkedValue < (*sourceValueInfo).minimumValue
- || checkedValue > (*sourceValueInfo).maximumValue) {
- return false;
- }
- }
- break;
-
- case QCameraImageProcessingControl::ContrastAdjustment: // falling back
- case QCameraImageProcessingControl::SaturationAdjustment: // falling back
- case QCameraImageProcessingControl::BrightnessAdjustment: // falling back
- case QCameraImageProcessingControl::SharpeningAdjustment: {
- const qint32 sourceValue = sourceImageProcessingParameterValue(
- value.toReal(), (*sourceValueInfo));
- if (sourceValue < (*sourceValueInfo).minimumValue
- || sourceValue > (*sourceValueInfo).maximumValue)
- return false;
- }
- break;
-
- default:
- return false;
- }
-
- return true;
-}
-
-QVariant DSCameraSession::imageProcessingParameter(
- QCameraImageProcessingControl::ProcessingParameter parameter) const
-{
- if (!m_graphBuilder) {
- auto it = m_pendingImageProcessingParametrs.find(parameter);
- return it != m_pendingImageProcessingParametrs.end() ? it.value() : QVariant();
- }
-
- const QCameraImageProcessingControl::ProcessingParameter resultingParameter =
- searchRelatedResultingParameter(parameter);
-
- QMap<QCameraImageProcessingControl::ProcessingParameter,
- ImageProcessingParameterInfo>::const_iterator sourceValueInfo =
- m_imageProcessingParametersInfos.constFind(resultingParameter);
-
- if (sourceValueInfo == m_imageProcessingParametersInfos.constEnd())
- return QVariant();
-
- switch (parameter) {
-
- case QCameraImageProcessingControl::WhiteBalancePreset:
- return QVariant::fromValue<QCameraImageProcessing::WhiteBalanceMode>(
- (*sourceValueInfo).capsFlags == VideoProcAmp_Flags_Auto
- ? QCameraImageProcessing::WhiteBalanceAuto
- : QCameraImageProcessing::WhiteBalanceManual);
-
- case QCameraImageProcessingControl::ColorTemperature:
- return QVariant::fromValue<qint32>((*sourceValueInfo).currentValue);
-
- case QCameraImageProcessingControl::ContrastAdjustment: // falling back
- case QCameraImageProcessingControl::SaturationAdjustment: // falling back
- case QCameraImageProcessingControl::BrightnessAdjustment: // falling back
- case QCameraImageProcessingControl::SharpeningAdjustment:
- return scaledImageProcessingParameterValue((*sourceValueInfo));
-
- default:
- return QVariant();
- }
-}
-
-void DSCameraSession::setImageProcessingParameter(
- QCameraImageProcessingControl::ProcessingParameter parameter,
- const QVariant &value)
-{
- if (!m_graphBuilder) {
- m_pendingImageProcessingParametrs.insert(parameter, value);
- return;
- }
-
- const QCameraImageProcessingControl::ProcessingParameter resultingParameter =
- searchRelatedResultingParameter(parameter);
-
- QMap<QCameraImageProcessingControl::ProcessingParameter,
- ImageProcessingParameterInfo>::iterator sourceValueInfo =
- m_imageProcessingParametersInfos.find(resultingParameter);
-
- if (sourceValueInfo == m_imageProcessingParametersInfos.end())
- return;
-
- LONG sourceValue = 0;
- LONG capsFlags = VideoProcAmp_Flags_Manual;
-
- switch (parameter) {
-
- case QCameraImageProcessingControl::WhiteBalancePreset: {
- const QCameraImageProcessing::WhiteBalanceMode checkedValue =
- value.value<QCameraImageProcessing::WhiteBalanceMode>();
- // Supports only the Manual and the Auto values
- if (checkedValue == QCameraImageProcessing::WhiteBalanceManual)
- capsFlags = VideoProcAmp_Flags_Manual;
- else if (checkedValue == QCameraImageProcessing::WhiteBalanceAuto)
- capsFlags = VideoProcAmp_Flags_Auto;
- else
- return;
-
- sourceValue = ((*sourceValueInfo).hasBeenExplicitlySet)
- ? (*sourceValueInfo).currentValue
- : (*sourceValueInfo).defaultValue;
- }
- break;
-
- case QCameraImageProcessingControl::ColorTemperature:
- sourceValue = value.isValid() ?
- value.value<qint32>() : (*sourceValueInfo).defaultValue;
- capsFlags = (*sourceValueInfo).capsFlags;
- break;
-
- case QCameraImageProcessingControl::ContrastAdjustment: // falling back
- case QCameraImageProcessingControl::SaturationAdjustment: // falling back
- case QCameraImageProcessingControl::BrightnessAdjustment: // falling back
- case QCameraImageProcessingControl::SharpeningAdjustment:
- if (value.isValid()) {
- sourceValue = sourceImageProcessingParameterValue(
- value.toReal(), (*sourceValueInfo));
- } else {
- sourceValue = (*sourceValueInfo).defaultValue;
- }
- break;
-
- default:
- return;
- }
-
- IAMVideoProcAmp *pVideoProcAmp = nullptr;
- HRESULT hr = m_graphBuilder->FindInterface(
- nullptr,
- nullptr,
- m_sourceFilter,
- IID_IAMVideoProcAmp,
- reinterpret_cast<void**>(&pVideoProcAmp)
- );
-
- if (FAILED(hr) || !pVideoProcAmp) {
- qWarning() << "failed to find the video proc amp";
- return;
- }
-
- hr = pVideoProcAmp->Set(
- (*sourceValueInfo).videoProcAmpProperty,
- sourceValue,
- capsFlags);
-
- pVideoProcAmp->Release();
-
- if (FAILED(hr)) {
- qWarning() << "failed to set the parameter value";
- } else {
- (*sourceValueInfo).capsFlags = capsFlags;
- (*sourceValueInfo).hasBeenExplicitlySet = true;
- (*sourceValueInfo).currentValue = sourceValue;
- }
-}
-
-bool DSCameraSession::getCameraControlInterface(IAMCameraControl **cameraControl) const
-{
- if (!m_sourceFilter) {
- qCDebug(qtDirectShowPlugin, "getCameraControlInterface failed: No capture filter!");
- return false;
- }
-
- if (!cameraControl) {
- qCDebug(qtDirectShowPlugin, "getCameraControlInterface failed: Invalid out argument!");
- return false;
- }
-
- if (FAILED(m_sourceFilter->QueryInterface(IID_IAMCameraControl, reinterpret_cast<void **>(cameraControl)))) {
- qCDebug(qtDirectShowPlugin, "getCameraControlInterface failed: Querying camera control failed!");
- return false;
- }
-
- return true;
-}
-
-bool DSCameraSession::isCaptureDestinationSupported(QCameraImageCapture::CaptureDestinations destination) const
-{
- return destination & (QCameraImageCapture::CaptureToFile | QCameraImageCapture::CaptureToBuffer);
-}
-
-QCameraImageCapture::CaptureDestinations DSCameraSession::captureDestination() const
-{
- return m_captureDestinations;
-}
-
-void DSCameraSession::setCaptureDestination(QCameraImageCapture::CaptureDestinations destinations)
-{
- if (m_captureDestinations == destinations)
- return;
-
- m_captureDestinations = destinations;
- Q_EMIT captureDestinationChanged(m_captureDestinations);
-}
-
-void DSCameraSession::addVideoProbe(DirectShowVideoProbeControl *probe)
-{
- const QMutexLocker locker(&m_probeMutex);
- m_videoProbeControl = probe;
-}
-
-void DSCameraSession::removeVideoProbe(DirectShowVideoProbeControl *probe)
-{
- Q_UNUSED(probe);
- Q_ASSERT(m_videoProbeControl == probe);
- const QMutexLocker locker(&m_probeMutex);
- m_videoProbeControl = nullptr;
-}
-
-bool DSCameraSession::load()
-{
- unload();
-
- setStatus(QCamera::LoadingStatus);
-
- bool succeeded = createFilterGraph();
- if (succeeded)
- setStatus(QCamera::LoadedStatus);
- else
- setStatus(QCamera::UnavailableStatus);
-
- return succeeded;
-}
-
-bool DSCameraSession::unload()
-{
- if (!m_graphBuilder)
- return false;
-
- if (!stopPreview())
- return false;
-
- setStatus(QCamera::UnloadingStatus);
-
- m_needsHorizontalMirroring = false;
- m_supportedViewfinderSettings.clear();
- m_supportedFormats.clear();
- SAFE_RELEASE(m_sourceFilter);
- SAFE_RELEASE(m_nullRendererFilter);
- SAFE_RELEASE(m_filterGraph);
- SAFE_RELEASE(m_graphBuilder);
- SAFE_RELEASE(m_outputPin);
-
- setStatus(QCamera::UnloadedStatus);
-
- return true;
-}
-
-bool DSCameraSession::startPreview()
-{
- if (m_previewStarted)
- return true;
-
- if (!m_graphBuilder)
- return false;
-
- setStatus(QCamera::StartingStatus);
-
- QString errorString;
- HRESULT hr = S_OK;
- IMediaControl* pControl = nullptr;
-
- if (!configurePreviewFormat()) {
- errorString = tr("Failed to configure preview format");
- goto failed;
- }
-
- if (!connectGraph()) {
- errorString = tr("Failed to connect graph");
- goto failed;
- }
-
- if (m_surface)
- m_surface->start(m_previewSurfaceFormat);
-
- hr = m_filterGraph->QueryInterface(IID_IMediaControl, reinterpret_cast<void**>(&pControl));
- if (FAILED(hr)) {
- errorString = tr("Failed to get stream control");
- goto failed;
- }
- hr = pControl->Run();
- pControl->Release();
-
- if (FAILED(hr)) {
- errorString = tr("Failed to start");
- goto failed;
- }
-
- setStatus(QCamera::ActiveStatus);
- m_previewStarted = true;
- return true;
-
-failed:
- // go back to a clean state
- if (m_surface && m_surface->isActive())
- m_surface->stop();
- disconnectGraph();
- setError(QCamera::CameraError, errorString, hr);
- return false;
-}
-
-bool DSCameraSession::stopPreview()
-{
- if (!m_previewStarted)
- return true;
-
- setStatus(QCamera::StoppingStatus);
-
- if (m_previewSampleGrabber)
- m_previewSampleGrabber->stop();
-
- QString errorString;
- IMediaControl* pControl = nullptr;
- HRESULT hr = m_filterGraph->QueryInterface(IID_IMediaControl,
- reinterpret_cast<void**>(&pControl));
- if (FAILED(hr)) {
- errorString = tr("Failed to get stream control");
- goto failed;
- }
-
- hr = pControl->Stop();
- pControl->Release();
- if (FAILED(hr)) {
- errorString = tr("Failed to stop");
- goto failed;
- }
-
- disconnectGraph();
-
- m_sourceFormat.clear();
-
- m_previewStarted = false;
- setStatus(QCamera::LoadedStatus);
- return true;
-
-failed:
- setError(QCamera::CameraError, errorString, hr);
- return false;
-}
-
-void DSCameraSession::setError(int error, const QString &errorString, HRESULT hr)
-{
- qErrnoWarning(hr, "[0x%x] %s", hr, qPrintable(errorString));
- emit cameraError(error, errorString);
- setStatus(QCamera::UnloadedStatus);
-}
-
-void DSCameraSession::setStatus(QCamera::Status status)
-{
- if (m_status == status)
- return;
-
- m_status = status;
- emit statusChanged(m_status);
-}
-
-bool DSCameraSession::isReadyForCapture()
-{
- return m_readyForCapture;
-}
-
-void DSCameraSession::updateReadyForCapture()
-{
- bool isReady = (m_status == QCamera::ActiveStatus && m_imageCaptureFileName.isEmpty());
- if (isReady != m_readyForCapture) {
- m_readyForCapture = isReady;
- emit readyForCaptureChanged(isReady);
- }
-}
-
-int DSCameraSession::captureImage(const QString &fileName)
-{
- ++m_imageIdCounter;
-
- if (!m_readyForCapture) {
- emit captureError(m_imageIdCounter, QCameraImageCapture::NotReadyError,
- tr("Camera not ready for capture"));
- return m_imageIdCounter;
- }
-
- const QString ext = !m_imageEncoderSettings.codec().isEmpty()
- ? m_imageEncoderSettings.codec().toLower()
- : QLatin1String("jpg");
- m_imageCaptureFileName = m_fileNameGenerator.generateFileName(fileName,
- QMediaStorageLocation::Pictures,
- QLatin1String("IMG_"),
- ext);
-
- updateReadyForCapture();
-
- m_captureMutex.lock();
- m_currentImageId = m_imageIdCounter;
- m_captureMutex.unlock();
-
- return m_imageIdCounter;
-}
-
-void DSCameraSession::onFrameAvailable(double time, const QByteArray &data)
-{
- // !!! Not called on the main thread
- Q_UNUSED(time);
-
- m_presentMutex.lock();
-
- // In case the source produces frames faster than we can display them,
- // only keep the most recent one
- m_currentFrame = QVideoFrame(new QMemoryVideoBuffer(data, m_stride),
- m_previewSize,
- m_previewPixelFormat);
-
- m_presentMutex.unlock();
-
- {
- const QMutexLocker locker(&m_probeMutex);
- if (m_currentFrame.isValid() && m_videoProbeControl)
- Q_EMIT m_videoProbeControl->videoFrameProbed(m_currentFrame);
- }
-
- // Image capture
- QMutexLocker locker(&m_captureMutex);
- if (m_currentImageId != -1 && !m_capturedFrame.isValid()) {
- m_capturedFrame = m_currentFrame;
- QMetaObject::invokeMethod(this, "imageExposed", Qt::QueuedConnection, Q_ARG(int, m_currentImageId));
- }
-
- QMetaObject::invokeMethod(this, "presentFrame", Qt::QueuedConnection);
-}
-
-void DSCameraSession::presentFrame()
-{
- // If no frames provided from ISampleGrabber for some time
- // the device might be potentially unplugged.
- m_deviceLostEventTimer.start(100);
-
- m_presentMutex.lock();
-
- if (m_currentFrame.isValid() && m_surface) {
- m_surface->present(m_currentFrame);
- m_currentFrame = QVideoFrame();
- }
-
- m_presentMutex.unlock();
-
- QImage captureImage;
- const int captureId = m_currentImageId;
-
- m_captureMutex.lock();
-
- if (m_capturedFrame.isValid()) {
-
- captureImage = m_capturedFrame.image();
-
- const bool needsVerticalMirroring = m_previewSurfaceFormat.scanLineDirection() != QVideoSurfaceFormat::TopToBottom;
- captureImage = captureImage.mirrored(m_needsHorizontalMirroring, needsVerticalMirroring); // also causes a deep copy of the data
-
- QtConcurrent::run(&DSCameraSession::processCapturedImage, this,
- m_currentImageId, m_captureDestinations, captureImage, m_imageCaptureFileName);
-
- m_imageCaptureFileName.clear();
- m_currentImageId = -1;
-
- m_capturedFrame = QVideoFrame();
- }
-
- m_captureMutex.unlock();
-
- if (!captureImage.isNull())
- emit imageCaptured(captureId, captureImage);
-
- updateReadyForCapture();
-}
-
-void DSCameraSession::processCapturedImage(int id,
- QCameraImageCapture::CaptureDestinations captureDestinations,
- const QImage &image,
- const QString &path)
-{
- const QString format = m_imageEncoderSettings.codec();
- if (captureDestinations & QCameraImageCapture::CaptureToFile) {
- if (image.save(path, !format.isEmpty() ? format.toUtf8().constData() : "JPG")) {
- Q_EMIT imageSaved(id, path);
- } else {
- Q_EMIT captureError(id, QCameraImageCapture::ResourceError,
- tr("Could not save image to file."));
- }
- }
-
- if (captureDestinations & QCameraImageCapture::CaptureToBuffer)
- Q_EMIT imageAvailable(id, QVideoFrame(image));
-}
-
-bool DSCameraSession::createFilterGraph()
-{
- // Previously containered in <qedit.h>.
- static const CLSID cLSID_NullRenderer = { 0xC1F400A4, 0x3F08, 0x11d3, { 0x9F, 0x0B, 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37 } };
-
- QString errorString;
- HRESULT hr;
- IMoniker* pMoniker = nullptr;
- ICreateDevEnum* pDevEnum = nullptr;
- IEnumMoniker* pEnum = nullptr;
-
- // Create the filter graph
- hr = CoCreateInstance(CLSID_FilterGraph, nullptr, CLSCTX_INPROC,
- IID_IGraphBuilder, reinterpret_cast<void**>(&m_filterGraph));
- if (FAILED(hr)) {
- errorString = tr("Failed to create filter graph");
- goto failed;
- }
-
- // Create the capture graph builder
- hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, nullptr, CLSCTX_INPROC,
- IID_ICaptureGraphBuilder2,
- reinterpret_cast<void**>(&m_graphBuilder));
- if (FAILED(hr)) {
- errorString = tr("Failed to create graph builder");
- goto failed;
- }
-
- // Attach the filter graph to the capture graph
- hr = m_graphBuilder->SetFiltergraph(m_filterGraph);
- if (FAILED(hr)) {
- errorString = tr("Failed to connect capture graph and filter graph");
- goto failed;
- }
-
- // Find the Capture device
- hr = CoCreateInstance(CLSID_SystemDeviceEnum, nullptr,
- CLSCTX_INPROC_SERVER, IID_ICreateDevEnum,
- reinterpret_cast<void**>(&pDevEnum));
- if (SUCCEEDED(hr)) {
- // Create an enumerator for the video capture category
- hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnum, 0);
- pDevEnum->Release();
- if (S_OK == hr) {
- pEnum->Reset();
- IMalloc *mallocInterface = nullptr;
- CoGetMalloc(1, (LPMALLOC*)&mallocInterface);
- //go through and find all video capture devices
- while (pEnum->Next(1, &pMoniker, nullptr) == S_OK) {
-
- BSTR strName = nullptr;
- hr = pMoniker->GetDisplayName(nullptr, nullptr, &strName);
- if (SUCCEEDED(hr)) {
- QString output = QString::fromWCharArray(strName);
- mallocInterface->Free(strName);
- if (m_sourceDeviceName.contains(output)) {
- hr = pMoniker->BindToObject(nullptr, nullptr, IID_IBaseFilter,
- reinterpret_cast<void**>(&m_sourceFilter));
- if (SUCCEEDED(hr)) {
- pMoniker->Release();
- break;
- }
- }
- }
- pMoniker->Release();
- }
- mallocInterface->Release();
- if (nullptr == m_sourceFilter)
- {
- if (m_sourceDeviceName.contains(QLatin1String("default")))
- {
- pEnum->Reset();
- // still have to loop to discard bind to storage failure case
- while (pEnum->Next(1, &pMoniker, nullptr) == S_OK) {
- IPropertyBag *pPropBag = nullptr;
-
- hr = pMoniker->BindToStorage(nullptr, nullptr, IID_IPropertyBag,
- reinterpret_cast<void**>(&pPropBag));
- if (FAILED(hr)) {
- pMoniker->Release();
- continue; // Don't panic yet
- }
-
- // No need to get the description, just grab it
-
- hr = pMoniker->BindToObject(nullptr, nullptr, IID_IBaseFilter,
- reinterpret_cast<void**>(&m_sourceFilter));
- pPropBag->Release();
- pMoniker->Release();
- if (SUCCEEDED(hr))
- break; // done, stop looping through
- qWarning("Object bind failed");
- }
- }
- }
- pEnum->Release();
- }
- }
-
- if (!m_sourceFilter) {
- errorString = tr("No capture device found");
- goto failed;
- }
-
- if (!DirectShowUtils::getPin(m_sourceFilter, PINDIR_OUTPUT, PIN_CATEGORY_CAPTURE, &m_outputPin, &hr))
- qWarning() << "Failed to get the pin for the video control:" << hr;
-
- // Sample grabber filter
- if (!m_previewSampleGrabber) {
- m_previewSampleGrabber = new DirectShowSampleGrabber(this);
- connect(m_previewSampleGrabber, &DirectShowSampleGrabber::bufferAvailable,
- this, &DSCameraSession::onFrameAvailable, Qt::DirectConnection);
- }
-
-
- // Null renderer. Input connected to the sample grabber's output. Simply
- // discard the samples it receives.
- hr = CoCreateInstance(cLSID_NullRenderer, nullptr, CLSCTX_INPROC,
- IID_IBaseFilter, (void**)&m_nullRendererFilter);
- if (FAILED(hr)) {
- errorString = tr("Failed to create null renderer");
- goto failed;
- }
-
- updateSourceCapabilities();
-
- return true;
-
-failed:
- m_needsHorizontalMirroring = false;
- SAFE_RELEASE(m_sourceFilter);
- SAFE_RELEASE(m_nullRendererFilter);
- SAFE_RELEASE(m_filterGraph);
- SAFE_RELEASE(m_graphBuilder);
- setError(QCamera::CameraError, errorString, hr);
-
- return false;
-}
-
-bool DSCameraSession::configurePreviewFormat()
-{
- // Resolve viewfinder settings
- int settingsIndex = 0;
- const QSize captureResolution = m_imageEncoderSettings.resolution();
- const QSize resolution = captureResolution.isValid() ? captureResolution : m_viewfinderSettings.resolution();
- QCameraViewfinderSettings resolvedViewfinderSettings;
- for (const QCameraViewfinderSettings &s : qAsConst(m_supportedViewfinderSettings)) {
- if ((resolution.isEmpty() || resolution == s.resolution())
- && (qFuzzyIsNull(m_viewfinderSettings.minimumFrameRate()) || qFuzzyCompare((float)m_viewfinderSettings.minimumFrameRate(), (float)s.minimumFrameRate()))
- && (qFuzzyIsNull(m_viewfinderSettings.maximumFrameRate()) || qFuzzyCompare((float)m_viewfinderSettings.maximumFrameRate(), (float)s.maximumFrameRate()))
- && (m_viewfinderSettings.pixelFormat() == QVideoFrame::Format_Invalid || m_viewfinderSettings.pixelFormat() == s.pixelFormat())
- && (m_viewfinderSettings.pixelAspectRatio().isEmpty() || m_viewfinderSettings.pixelAspectRatio() == s.pixelAspectRatio())) {
- resolvedViewfinderSettings = s;
- break;
- }
- ++settingsIndex;
- }
-
- if (resolvedViewfinderSettings.isNull()) {
- qWarning("Invalid viewfinder settings");
- return false;
- }
-
- m_actualViewfinderSettings = resolvedViewfinderSettings;
-
- m_sourceFormat = m_supportedFormats[settingsIndex];
- // Set frame rate.
- // We don't care about the minimumFrameRate, DirectShow only allows to set an
- // average frame rate, so set that to the maximumFrameRate.
- VIDEOINFOHEADER *videoInfo = reinterpret_cast<VIDEOINFOHEADER*>(m_sourceFormat->pbFormat);
- videoInfo->AvgTimePerFrame = 10000000 / resolvedViewfinderSettings.maximumFrameRate();
-
- m_previewPixelFormat = resolvedViewfinderSettings.pixelFormat();
- const AM_MEDIA_TYPE *resolvedGrabberFormat = &m_sourceFormat;
-
- if (m_surface) {
- const auto surfaceFormats = m_surface->supportedPixelFormats(QAbstractVideoBuffer::NoHandle);
- if (!surfaceFormats.contains(m_previewPixelFormat)) {
- if (surfaceFormats.contains(QVideoFrame::Format_RGB32)) {
- // As a fallback, we support RGB32, if the capture source doesn't support
- // that format, the graph builder will automatically insert a
- // converter (when possible).
-
- static const AM_MEDIA_TYPE rgb32GrabberFormat { MEDIATYPE_Video, MEDIASUBTYPE_ARGB32, 0, 0, 0, FORMAT_VideoInfo, nullptr, 0, nullptr};
- resolvedGrabberFormat = &rgb32GrabberFormat;
- m_previewPixelFormat = QVideoFrame::Format_RGB32;
-
- } else {
- qWarning() << "Video surface needs to support at least RGB32 pixel format";
- return false;
- }
- }
- }
-
- m_previewSize = resolvedViewfinderSettings.resolution();
- m_previewSurfaceFormat = QVideoSurfaceFormat(m_previewSize,
- m_previewPixelFormat,
- QAbstractVideoBuffer::NoHandle);
- m_previewSurfaceFormat.setScanLineDirection(DirectShowMediaType::scanLineDirection(m_previewPixelFormat, videoInfo->bmiHeader));
- m_stride = DirectShowMediaType::bytesPerLine(m_previewSurfaceFormat);
-
- HRESULT hr;
- IAMStreamConfig* pConfig = nullptr;
- hr = m_graphBuilder->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,
- m_sourceFilter, IID_IAMStreamConfig,
- reinterpret_cast<void**>(&pConfig));
- if (FAILED(hr)) {
- qWarning() << "Failed to get config for capture device";
- return false;
- }
-
- hr = pConfig->SetFormat(&m_sourceFormat);
-
- pConfig->Release();
-
- if (FAILED(hr)) {
- qWarning() << "Unable to set video format on capture device";
- return false;
- }
-
- if (!m_previewSampleGrabber->setMediaType(resolvedGrabberFormat))
- return false;
-
- m_previewSampleGrabber->start(DirectShowSampleGrabber::CallbackMethod::BufferCB);
-
- return true;
-}
-
-void DSCameraSession::updateImageProcessingParametersInfos()
-{
- if (!m_graphBuilder) {
- qWarning() << "failed to access to the graph builder";
- return;
- }
-
- IAMVideoProcAmp *pVideoProcAmp = nullptr;
- const HRESULT hr = m_graphBuilder->FindInterface(
- nullptr,
- nullptr,
- m_sourceFilter,
- IID_IAMVideoProcAmp,
- reinterpret_cast<void**>(&pVideoProcAmp)
- );
-
- if (FAILED(hr) || !pVideoProcAmp) {
- qWarning() << "failed to find the video proc amp";
- return;
- }
-
- for (int property = VideoProcAmp_Brightness; property <= VideoProcAmp_Gain; ++property) {
-
- QCameraImageProcessingControl::ProcessingParameter processingParameter; // not initialized
-
- switch (property) {
- case VideoProcAmp_Brightness:
- processingParameter = QCameraImageProcessingControl::BrightnessAdjustment;
- break;
- case VideoProcAmp_Contrast:
- processingParameter = QCameraImageProcessingControl::ContrastAdjustment;
- break;
- case VideoProcAmp_Saturation:
- processingParameter = QCameraImageProcessingControl::SaturationAdjustment;
- break;
- case VideoProcAmp_Sharpness:
- processingParameter = QCameraImageProcessingControl::SharpeningAdjustment;
- break;
- case VideoProcAmp_WhiteBalance:
- processingParameter = QCameraImageProcessingControl::ColorTemperature;
- break;
- default: // unsupported or not implemented yet parameter
- continue;
- }
-
- ImageProcessingParameterInfo sourceValueInfo;
- LONG steppingDelta = 0;
-
- HRESULT hr = pVideoProcAmp->GetRange(
- property,
- &sourceValueInfo.minimumValue,
- &sourceValueInfo.maximumValue,
- &steppingDelta,
- &sourceValueInfo.defaultValue,
- &sourceValueInfo.capsFlags);
-
- if (FAILED(hr))
- continue;
-
- hr = pVideoProcAmp->Get(
- property,
- &sourceValueInfo.currentValue,
- &sourceValueInfo.capsFlags);
-
- if (FAILED(hr))
- continue;
-
- sourceValueInfo.videoProcAmpProperty = static_cast<VideoProcAmpProperty>(property);
-
- m_imageProcessingParametersInfos.insert(processingParameter, sourceValueInfo);
- }
-
- pVideoProcAmp->Release();
-
- for (auto it = m_pendingImageProcessingParametrs.cbegin();
- it != m_pendingImageProcessingParametrs.cend();
- ++it) {
- setImageProcessingParameter(it.key(), it.value());
- }
- m_pendingImageProcessingParametrs.clear();
-}
-
-bool DSCameraSession::connectGraph()
-{
- HRESULT hr = m_filterGraph->AddFilter(m_sourceFilter, L"Capture Filter");
- if (FAILED(hr)) {
- qWarning() << "failed to add capture filter to graph";
- return false;
- }
-
- if (FAILED(m_filterGraph->AddFilter(m_previewSampleGrabber->filter(), L"Sample Grabber"))) {
- qWarning() << "failed to add sample grabber to graph";
- return false;
- }
-
- hr = m_filterGraph->AddFilter(m_nullRendererFilter, L"Null Renderer");
- if (FAILED(hr)) {
- qWarning() << "failed to add null renderer to graph";
- return false;
- }
-
- hr = m_graphBuilder->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,
- m_sourceFilter,
- m_previewSampleGrabber->filter(),
- m_nullRendererFilter);
- if (FAILED(hr)) {
- qWarning() << "Graph failed to connect filters" << hr;
- return false;
- }
-
- return true;
-}
-
-void DSCameraSession::disconnectGraph()
-{
- // To avoid increasing the memory usage every time the graph is re-connected it's
- // important that all filters are released; also the ones added by the "Intelligent Connect".
- IEnumFilters *enumFilters = nullptr;
- if (SUCCEEDED(m_filterGraph->EnumFilters(&enumFilters))) {
- IBaseFilter *filter = nullptr;
- while (enumFilters->Next(1, &filter, nullptr) == S_OK) {
- m_filterGraph->RemoveFilter(filter);
- enumFilters->Reset();
- filter->Release();
- }
- enumFilters->Release();
- }
-}
-
-static bool qt_frameRateRangeGreaterThan(const QCamera::FrameRateRange &r1, const QCamera::FrameRateRange &r2)
-{
- return r1.maximumFrameRate > r2.maximumFrameRate;
-}
-
-void DSCameraSession::updateSourceCapabilities()
-{
- HRESULT hr;
- AM_MEDIA_TYPE *pmt = nullptr;
- VIDEOINFOHEADER *pvi = nullptr;
- VIDEO_STREAM_CONFIG_CAPS scc;
- IAMStreamConfig* pConfig = nullptr;
-
- m_supportedViewfinderSettings.clear();
- m_needsHorizontalMirroring = false;
- m_supportedFormats.clear();
- m_imageProcessingParametersInfos.clear();
-
- IAMVideoControl *pVideoControl = nullptr;
- hr = m_graphBuilder->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,
- m_sourceFilter, IID_IAMVideoControl,
- reinterpret_cast<void**>(&pVideoControl));
- if (FAILED(hr)) {
- qWarning() << "Failed to get the video control";
- } else if (m_outputPin) {
- long supportedModes;
- hr = pVideoControl->GetCaps(m_outputPin, &supportedModes);
- if (FAILED(hr)) {
- qWarning() << "Failed to get the supported modes of the video control";
- } else if (supportedModes & VideoControlFlag_FlipHorizontal) {
- long mode;
- hr = pVideoControl->GetMode(m_outputPin, &mode);
- if (FAILED(hr))
- qWarning() << "Failed to get the mode of the video control";
- else if (supportedModes & VideoControlFlag_FlipHorizontal)
- m_needsHorizontalMirroring = (mode & VideoControlFlag_FlipHorizontal);
- }
- pVideoControl->Release();
- }
-
- hr = m_graphBuilder->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,
- m_sourceFilter, IID_IAMStreamConfig,
- reinterpret_cast<void**>(&pConfig));
- if (FAILED(hr)) {
- qWarning() << "failed to get config on capture device";
- return;
- }
-
- int iCount;
- int iSize;
- hr = pConfig->GetNumberOfCapabilities(&iCount, &iSize);
- if (FAILED(hr)) {
- qWarning() << "failed to get capabilities";
- return;
- }
-
- for (int iIndex = 0; iIndex < iCount; ++iIndex) {
- hr = pConfig->GetStreamCaps(iIndex, &pmt, reinterpret_cast<BYTE*>(&scc));
- if (hr == S_OK) {
- QVideoFrame::PixelFormat pixelFormat = DirectShowMediaType::pixelFormatFromType(pmt);
-
- if (pmt->majortype == MEDIATYPE_Video
- && pmt->formattype == FORMAT_VideoInfo
- && pixelFormat != QVideoFrame::Format_Invalid) {
-
- pvi = reinterpret_cast<VIDEOINFOHEADER*>(pmt->pbFormat);
- QSize resolution(pvi->bmiHeader.biWidth, pvi->bmiHeader.biHeight);
-
- QList<QCamera::FrameRateRange> frameRateRanges;
-
- if (pVideoControl && m_outputPin) {
- long listSize = 0;
- LONGLONG *frameRates = nullptr;
- SIZE size = { resolution.width(), resolution.height() };
- hr = pVideoControl->GetFrameRateList(m_outputPin, iIndex, size, &listSize, &frameRates);
- if (hr == S_OK && listSize > 0 && frameRates) {
- for (long i = 0; i < listSize; ++i) {
- qreal fr = qreal(10000000) / frameRates[i];
- frameRateRanges.append(QCamera::FrameRateRange(fr, fr));
- }
-
- // Make sure higher frame rates come first
- std::sort(frameRateRanges.begin(), frameRateRanges.end(), qt_frameRateRangeGreaterThan);
- }
-
- CoTaskMemFree(frameRates);
- }
-
- if (frameRateRanges.isEmpty()) {
- frameRateRanges.append(QCamera::FrameRateRange(qreal(10000000) / scc.MaxFrameInterval,
- qreal(10000000) / scc.MinFrameInterval));
- }
-
- for (const QCamera::FrameRateRange &frameRateRange : qAsConst(frameRateRanges)) {
- QCameraViewfinderSettings settings;
- settings.setResolution(resolution);
- settings.setMinimumFrameRate(frameRateRange.minimumFrameRate);
- settings.setMaximumFrameRate(frameRateRange.maximumFrameRate);
- settings.setPixelFormat(pixelFormat);
- settings.setPixelAspectRatio(1, 1);
- m_supportedViewfinderSettings.append(settings);
- m_supportedFormats.append(DirectShowMediaType(*pmt));
- }
- } else {
- OLECHAR *guidString = nullptr;
- StringFromCLSID(pmt->subtype, &guidString);
- if (guidString)
- qWarning() << "Unsupported media type:" << QString::fromWCharArray(guidString);
- ::CoTaskMemFree(guidString);
- }
-
- DirectShowMediaType::deleteType(pmt);
- }
- }
-
- pConfig->Release();
-
- updateImageProcessingParametersInfos();
-}
-
-QList<QSize> DSCameraSession::supportedResolutions(bool *continuous) const
-{
- if (continuous)
- *continuous = false;
-
- QList<QSize> res;
- for (auto &settings : m_supportedViewfinderSettings) {
- auto size = settings.resolution();
- if (!res.contains(size))
- res << size;
- }
-
- std::sort(res.begin(), res.end(), [](const QSize &r1, const QSize &r2) {
- return qlonglong(r1.width()) * r1.height() < qlonglong(r2.width()) * r2.height();
- });
-
- return res;
-}
-
-QT_END_NAMESPACE