From 5a0a3791a1e5e97612ee11833aa084ae76a8b725 Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Fri, 19 Dec 2014 20:08:58 +0100 Subject: DirectShow: implemented QCameraViewfinderSettingsControl2. Change-Id: I42ed49676e2fbc7207d8fe4579ad1fc0d62df138 Reviewed-by: Christian Stromme --- src/plugins/directshow/camera/camera.pri | 6 +- src/plugins/directshow/camera/dscameraservice.cpp | 6 + src/plugins/directshow/camera/dscameraservice.h | 3 +- src/plugins/directshow/camera/dscamerasession.cpp | 191 +++++++++++++++------ src/plugins/directshow/camera/dscamerasession.h | 14 +- .../camera/dscameraviewfindersettingscontrol.cpp | 60 +++++++ .../camera/dscameraviewfindersettingscontrol.h | 59 +++++++ 7 files changed, 284 insertions(+), 55 deletions(-) create mode 100644 src/plugins/directshow/camera/dscameraviewfindersettingscontrol.cpp create mode 100644 src/plugins/directshow/camera/dscameraviewfindersettingscontrol.h (limited to 'src/plugins/directshow/camera') diff --git a/src/plugins/directshow/camera/camera.pri b/src/plugins/directshow/camera/camera.pri index 75fca4aad..3a532f472 100644 --- a/src/plugins/directshow/camera/camera.pri +++ b/src/plugins/directshow/camera/camera.pri @@ -13,7 +13,8 @@ HEADERS += \ $$PWD/dsvideodevicecontrol.h \ $$PWD/dsimagecapturecontrol.h \ $$PWD/dscamerasession.h \ - $$PWD/directshowglobal.h + $$PWD/directshowglobal.h \ + $$PWD/dscameraviewfindersettingscontrol.h SOURCES += \ $$PWD/dscameraservice.cpp \ @@ -21,7 +22,8 @@ SOURCES += \ $$PWD/dsvideorenderer.cpp \ $$PWD/dsvideodevicecontrol.cpp \ $$PWD/dsimagecapturecontrol.cpp \ - $$PWD/dscamerasession.cpp + $$PWD/dscamerasession.cpp \ + $$PWD/dscameraviewfindersettingscontrol.cpp *-msvc*:INCLUDEPATH += $$(DXSDK_DIR)/include LIBS += -lstrmiids -ldmoguids -luuid -lmsdmo -lole32 -loleaut32 diff --git a/src/plugins/directshow/camera/dscameraservice.cpp b/src/plugins/directshow/camera/dscameraservice.cpp index a7072ed13..9fcd4de70 100644 --- a/src/plugins/directshow/camera/dscameraservice.cpp +++ b/src/plugins/directshow/camera/dscameraservice.cpp @@ -40,6 +40,7 @@ #include "dsvideorenderer.h" #include "dsvideodevicecontrol.h" #include "dsimagecapturecontrol.h" +#include "dscameraviewfindersettingscontrol.h" QT_BEGIN_NAMESPACE @@ -51,11 +52,13 @@ DSCameraService::DSCameraService(QObject *parent): m_control = new DSCameraControl(m_session); m_videoDevice = new DSVideoDeviceControl(m_session); m_imageCapture = new DSImageCaptureControl(m_session); + m_viewfinderSettings = new DSCameraViewfinderSettingsControl(m_session); } DSCameraService::~DSCameraService() { delete m_control; + delete m_viewfinderSettings; delete m_videoDevice; delete m_videoRenderer; delete m_imageCapture; @@ -80,6 +83,9 @@ QMediaControl* DSCameraService::requestControl(const char *name) if (qstrcmp(name,QVideoDeviceSelectorControl_iid) == 0) return m_videoDevice; + if (qstrcmp(name, QCameraViewfinderSettingsControl2_iid) == 0) + return m_viewfinderSettings; + return 0; } diff --git a/src/plugins/directshow/camera/dscameraservice.h b/src/plugins/directshow/camera/dscameraservice.h index e40cd02e8..c3c881d0e 100644 --- a/src/plugins/directshow/camera/dscameraservice.h +++ b/src/plugins/directshow/camera/dscameraservice.h @@ -45,7 +45,7 @@ class DSCameraSession; class DSVideoOutputControl; class DSVideoDeviceControl; class DSImageCaptureControl; - +class DSCameraViewfinderSettingsControl; class DSCameraService : public QMediaService { @@ -65,6 +65,7 @@ private: DSVideoDeviceControl *m_videoDevice; QMediaControl *m_videoRenderer; DSImageCaptureControl *m_imageCapture; + DSCameraViewfinderSettingsControl *m_viewfinderSettings; }; QT_END_NAMESPACE diff --git a/src/plugins/directshow/camera/dscamerasession.cpp b/src/plugins/directshow/camera/dscamerasession.cpp index 3682ec417..375c05118 100644 --- a/src/plugins/directshow/camera/dscamerasession.cpp +++ b/src/plugins/directshow/camera/dscamerasession.cpp @@ -78,9 +78,6 @@ void _FreeMediaType(AM_MEDIA_TYPE& mt) } } // end namespace -typedef QList SizeList; -Q_GLOBAL_STATIC(SizeList, commonPreviewResolutions) - static HRESULT getPin(IBaseFilter *filter, PIN_DIRECTION pinDir, IPin **pin); @@ -148,6 +145,42 @@ private: DSCameraSession *m_session; }; +QVideoFrame::PixelFormat pixelFormatFromMediaSubtype(GUID uid) +{ + if (uid == MEDIASUBTYPE_ARGB32) + return QVideoFrame::Format_ARGB32; + else if (uid == MEDIASUBTYPE_RGB32) + return QVideoFrame::Format_RGB32; + else if (uid == MEDIASUBTYPE_RGB24) + return QVideoFrame::Format_RGB24; + else if (uid == MEDIASUBTYPE_RGB565) + return QVideoFrame::Format_RGB565; + else if (uid == MEDIASUBTYPE_RGB555) + return QVideoFrame::Format_RGB555; + else if (uid == MEDIASUBTYPE_AYUV) + return QVideoFrame::Format_AYUV444; + else if (uid == MEDIASUBTYPE_I420 || uid == MEDIASUBTYPE_IYUV) + return QVideoFrame::Format_YUV420P; + else if (uid == MEDIASUBTYPE_YV12) + return QVideoFrame::Format_YV12; + else if (uid == MEDIASUBTYPE_UYVY) + return QVideoFrame::Format_UYVY; + else if (uid == MEDIASUBTYPE_YUYV || uid == MEDIASUBTYPE_YUY2) + return QVideoFrame::Format_YUYV; + else if (uid == MEDIASUBTYPE_NV12) + return QVideoFrame::Format_NV12; + else if (uid == MEDIASUBTYPE_IMC1) + return QVideoFrame::Format_IMC1; + else if (uid == MEDIASUBTYPE_IMC2) + return QVideoFrame::Format_IMC2; + else if (uid == MEDIASUBTYPE_IMC3) + return QVideoFrame::Format_IMC3; + else if (uid == MEDIASUBTYPE_IMC4) + return QVideoFrame::Format_IMC4; + else + return QVideoFrame::Format_Invalid; +} + DSCameraSession::DSCameraSession(QObject *parent) : QObject(parent) @@ -167,7 +200,7 @@ DSCameraSession::DSCameraSession(QObject *parent) , m_currentImageId(-1) , m_status(QCamera::UnloadedStatus) { - ZeroMemory(&m_sourcePreferredFormat, sizeof(m_sourcePreferredFormat)); + ZeroMemory(&m_sourceFormat, sizeof(m_sourceFormat)); connect(this, SIGNAL(statusChanged(QCamera::Status)), this, SLOT(updateReadyForCapture())); @@ -188,6 +221,16 @@ 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; +} + bool DSCameraSession::load() { unload(); @@ -214,9 +257,10 @@ bool DSCameraSession::unload() setStatus(QCamera::UnloadingStatus); m_needsHorizontalMirroring = false; - m_sourcePreferredResolution = QSize(); - _FreeMediaType(m_sourcePreferredFormat); - ZeroMemory(&m_sourcePreferredFormat, sizeof(m_sourcePreferredFormat)); + m_supportedViewfinderSettings.clear(); + Q_FOREACH (AM_MEDIA_TYPE f, m_supportedFormats) + _FreeMediaType(f); + m_supportedFormats.clear(); SAFE_RELEASE(m_sourceFilter); SAFE_RELEASE(m_previewSampleGrabber); SAFE_RELEASE(m_previewFilter); @@ -302,6 +346,9 @@ bool DSCameraSession::stopPreview() disconnectGraph(); + _FreeMediaType(m_sourceFormat); + ZeroMemory(&m_sourceFormat, sizeof(m_sourceFormat)); + m_previewStarted = false; setStatus(QCamera::LoadedStatus); return true; @@ -581,9 +628,6 @@ bool DSCameraSession::createFilterGraph() failed: m_needsHorizontalMirroring = false; - m_sourcePreferredResolution = QSize(); - _FreeMediaType(m_sourcePreferredFormat); - ZeroMemory(&m_sourcePreferredFormat, sizeof(m_sourcePreferredFormat)); SAFE_RELEASE(m_sourceFilter); SAFE_RELEASE(m_previewSampleGrabber); SAFE_RELEASE(m_previewFilter); @@ -596,6 +640,34 @@ failed: bool DSCameraSession::configurePreviewFormat() { + // Resolve viewfinder settings + int settingsIndex = 0; + QCameraViewfinderSettings resolvedViewfinderSettings; + Q_FOREACH (const QCameraViewfinderSettings &s, m_supportedViewfinderSettings) { + if ((m_viewfinderSettings.resolution().isEmpty() || m_viewfinderSettings.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())) { + resolvedViewfinderSettings = s; + break; + } + ++settingsIndex; + } + + if (resolvedViewfinderSettings.isNull()) { + qWarning("Invalid viewfinder settings"); + return false; + } + + m_actualViewfinderSettings = resolvedViewfinderSettings; + + _CopyMediaType(&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(m_sourceFormat.pbFormat); + videoInfo->AvgTimePerFrame = 10000000 / resolvedViewfinderSettings.maximumFrameRate(); + // We only support RGB32, if the capture source doesn't support // that format, the graph builder will automatically insert a // converter. @@ -607,7 +679,7 @@ bool DSCameraSession::configurePreviewFormat() } m_previewPixelFormat = QVideoFrame::Format_RGB32; - m_previewSize = m_sourcePreferredResolution; + m_previewSize = resolvedViewfinderSettings.resolution(); m_previewSurfaceFormat = QVideoSurfaceFormat(m_previewSize, m_previewPixelFormat, QAbstractVideoBuffer::NoHandle); @@ -624,7 +696,7 @@ bool DSCameraSession::configurePreviewFormat() return false; } - hr = pConfig->SetFormat(&m_sourcePreferredFormat); + hr = pConfig->SetFormat(&m_sourceFormat); pConfig->Release(); @@ -716,6 +788,11 @@ void DSCameraSession::disconnectGraph() m_filterGraph->RemoveFilter(m_sourceFilter); } +static bool qt_frameRateRangeGreaterThan(const QCamera::FrameRateRange &r1, const QCamera::FrameRateRange &r2) +{ + return r1.second > r2.second; +} + void DSCameraSession::updateSourceCapabilities() { HRESULT hr; @@ -724,10 +801,11 @@ void DSCameraSession::updateSourceCapabilities() VIDEO_STREAM_CONFIG_CAPS scc; IAMStreamConfig* pConfig = 0; + m_supportedViewfinderSettings.clear(); m_needsHorizontalMirroring = false; - m_sourcePreferredResolution = QSize(); - _FreeMediaType(m_sourcePreferredFormat); - ZeroMemory(&m_sourcePreferredFormat, sizeof(m_sourcePreferredFormat)); + Q_FOREACH (AM_MEDIA_TYPE f, m_supportedFormats) + _FreeMediaType(f); + m_supportedFormats.clear(); IAMVideoControl *pVideoControl = 0; hr = m_graphBuilder->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, @@ -774,53 +852,68 @@ void DSCameraSession::updateSourceCapabilities() return; } - // Use preferred pixel format (first in the list) - // Then, pick the highest available resolution among the typical resolutions - // used for camera preview. - if (commonPreviewResolutions->isEmpty()) - populateCommonResolutions(); - - long maxPixelCount = 0; for (int iIndex = 0; iIndex < iCount; ++iIndex) { hr = pConfig->GetStreamCaps(iIndex, &pmt, reinterpret_cast(&scc)); if (hr == S_OK) { - if ((pmt->majortype == MEDIATYPE_Video) && - (pmt->formattype == FORMAT_VideoInfo) && - (!m_sourcePreferredFormat.cbFormat || - m_sourcePreferredFormat.subtype == pmt->subtype)) { + QVideoFrame::PixelFormat pixelFormat = pixelFormatFromMediaSubtype(pmt->subtype); - pvi = reinterpret_cast(pmt->pbFormat); + if (pmt->majortype == MEDIATYPE_Video + && pmt->formattype == FORMAT_VideoInfo + && pixelFormat != QVideoFrame::Format_Invalid) { + pvi = reinterpret_cast(pmt->pbFormat); QSize resolution(pvi->bmiHeader.biWidth, pvi->bmiHeader.biHeight); - long pixelCount = resolution.width() * resolution.height(); - - if (!m_sourcePreferredFormat.cbFormat || - (pixelCount > maxPixelCount && commonPreviewResolutions->contains(resolution))) { - _FreeMediaType(m_sourcePreferredFormat); - _CopyMediaType(&m_sourcePreferredFormat, pmt); - m_sourcePreferredResolution = resolution; - maxPixelCount = pixelCount; + + QList frameRateRanges; + + if (pVideoControl) { + IPin *pPin = 0; + hr = getPin(m_sourceFilter, PINDIR_OUTPUT, &pPin); + if (FAILED(hr)) { + qWarning() << "Failed to get the pin for the video control"; + } else { + long listSize = 0; + LONGLONG *frameRates = 0; + SIZE size = { resolution.width(), resolution.height() }; + if (SUCCEEDED(pVideoControl->GetFrameRateList(pPin, iIndex, size, + &listSize, &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); + } + pPin->Release(); + } } + + if (frameRateRanges.isEmpty()) { + frameRateRanges.append(QCamera::FrameRateRange(qreal(10000000) / scc.MaxFrameInterval, + qreal(10000000) / scc.MinFrameInterval)); + } + + Q_FOREACH (const QCamera::FrameRateRange &frameRateRange, frameRateRanges) { + QCameraViewfinderSettings settings; + settings.setResolution(resolution); + settings.setMinimumFrameRate(frameRateRange.first); + settings.setMaximumFrameRate(frameRateRange.second); + settings.setPixelFormat(pixelFormat); + m_supportedViewfinderSettings.append(settings); + + AM_MEDIA_TYPE format; + _CopyMediaType(&format, pmt); + m_supportedFormats.append(format); + } + + } _FreeMediaType(*pmt); } } pConfig->Release(); - - if (!m_sourcePreferredResolution.isValid()) - m_sourcePreferredResolution = QSize(640, 480); -} - -void DSCameraSession::populateCommonResolutions() -{ - commonPreviewResolutions->append(QSize(1920, 1080)); // 1080p - commonPreviewResolutions->append(QSize(1280, 720)); // 720p - commonPreviewResolutions->append(QSize(1024, 576)); // WSVGA - commonPreviewResolutions->append(QSize(720, 480)); // 480p (16:9) - commonPreviewResolutions->append(QSize(640, 480)); // 480p (4:3) - commonPreviewResolutions->append(QSize(352, 288)); // CIF - commonPreviewResolutions->append(QSize(320, 240)); // QVGA } HRESULT getPin(IBaseFilter *pFilter, PIN_DIRECTION PinDir, IPin **ppPin) diff --git a/src/plugins/directshow/camera/dscamerasession.h b/src/plugins/directshow/camera/dscamerasession.h index f2ff39256..9ac121463 100644 --- a/src/plugins/directshow/camera/dscamerasession.h +++ b/src/plugins/directshow/camera/dscamerasession.h @@ -91,6 +91,12 @@ public: void setSurface(QAbstractVideoSurface* surface); + QCameraViewfinderSettings viewfinderSettings() const; + void setViewfinderSettings(const QCameraViewfinderSettings &settings); + + QList supportedViewfinderSettings() const + { return m_supportedViewfinderSettings; } + Q_SIGNALS: void statusChanged(QCamera::Status); void imageExposed(int id); @@ -105,7 +111,6 @@ private Q_SLOTS: private: void setStatus(QCamera::Status status); - void populateCommonResolutions(); void onFrameAvailable(const char *frameData, long len); void saveCapturedImage(int id, const QImage &image, const QString &path); @@ -126,9 +131,10 @@ private: // Source (camera) QString m_sourceDeviceName; IBaseFilter* m_sourceFilter; - AM_MEDIA_TYPE m_sourcePreferredFormat; - QSize m_sourcePreferredResolution; bool m_needsHorizontalMirroring; + QList m_supportedFormats; + QList m_supportedViewfinderSettings; + AM_MEDIA_TYPE m_sourceFormat; // Preview IBaseFilter *m_previewFilter; @@ -140,6 +146,8 @@ private: QVideoSurfaceFormat m_previewSurfaceFormat; QVideoFrame::PixelFormat m_previewPixelFormat; QSize m_previewSize; + QCameraViewfinderSettings m_viewfinderSettings; + QCameraViewfinderSettings m_actualViewfinderSettings; // Image capture QString m_imageCaptureFileName; diff --git a/src/plugins/directshow/camera/dscameraviewfindersettingscontrol.cpp b/src/plugins/directshow/camera/dscameraviewfindersettingscontrol.cpp new file mode 100644 index 000000000..e3215a89b --- /dev/null +++ b/src/plugins/directshow/camera/dscameraviewfindersettingscontrol.cpp @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "dscameraviewfindersettingscontrol.h" +#include "dscamerasession.h" + +QT_BEGIN_NAMESPACE + +DSCameraViewfinderSettingsControl::DSCameraViewfinderSettingsControl(DSCameraSession *session) + : QCameraViewfinderSettingsControl2(session) + , m_session(session) +{ +} + +QList DSCameraViewfinderSettingsControl::supportedViewfinderSettings() const +{ + return m_session->supportedViewfinderSettings(); +} + +QCameraViewfinderSettings DSCameraViewfinderSettingsControl::viewfinderSettings() const +{ + return m_session->viewfinderSettings(); +} + +void DSCameraViewfinderSettingsControl::setViewfinderSettings(const QCameraViewfinderSettings &settings) +{ + m_session->setViewfinderSettings(settings); +} + +QT_END_NAMESPACE diff --git a/src/plugins/directshow/camera/dscameraviewfindersettingscontrol.h b/src/plugins/directshow/camera/dscameraviewfindersettingscontrol.h new file mode 100644 index 000000000..30d4122a0 --- /dev/null +++ b/src/plugins/directshow/camera/dscameraviewfindersettingscontrol.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DSCAMERAVIEWFINDERSETTINGSCONTROL_H +#define DSCAMERAVIEWFINDERSETTINGSCONTROL_H + +#include + +QT_BEGIN_NAMESPACE + +class DSCameraSession; + +class DSCameraViewfinderSettingsControl : public QCameraViewfinderSettingsControl2 +{ +public: + DSCameraViewfinderSettingsControl(DSCameraSession *session); + + QList supportedViewfinderSettings() const; + + QCameraViewfinderSettings viewfinderSettings() const; + void setViewfinderSettings(const QCameraViewfinderSettings &settings); + +private: + DSCameraSession *m_session; +}; + +QT_END_NAMESPACE + +#endif // DSCAMERAVIEWFINDERSETTINGSCONTROL_H -- cgit v1.2.3