summaryrefslogtreecommitdiffstats
path: root/src/plugins/multimedia/ffmpeg/qwindowscamera.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/multimedia/ffmpeg/qwindowscamera.cpp')
-rw-r--r--src/plugins/multimedia/ffmpeg/qwindowscamera.cpp255
1 files changed, 105 insertions, 150 deletions
diff --git a/src/plugins/multimedia/ffmpeg/qwindowscamera.cpp b/src/plugins/multimedia/ffmpeg/qwindowscamera.cpp
index b6e031633..d298e2c99 100644
--- a/src/plugins/multimedia/ffmpeg/qwindowscamera.cpp
+++ b/src/plugins/multimedia/ffmpeg/qwindowscamera.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2022 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$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwindowscamera_p.h"
#include "qsemaphore.h"
@@ -43,53 +7,23 @@
#include <private/qmemoryvideobuffer_p.h>
#include <private/qwindowsmfdefs_p.h>
+#include <private/qwindowsmultimediautils_p.h>
+#include <private/qcomobject_p.h>
#include <mfapi.h>
#include <mfidl.h>
-#include <Mferror.h>
-#include <Mfreadwrite.h>
+#include <mferror.h>
+#include <mfreadwrite.h>
#include <system_error>
QT_BEGIN_NAMESPACE
-class CameraReaderCallback : public IMFSourceReaderCallback
+using namespace QWindowsMultimediaUtils;
+
+class CameraReaderCallback : public QComObject<IMFSourceReaderCallback>
{
public:
- CameraReaderCallback() : m_cRef(1) {}
- virtual ~CameraReaderCallback() {}
-
- //from IUnknown
- STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObject) override
- {
- if (!ppvObject)
- return E_POINTER;
- if (riid == IID_IMFSourceReaderCallback) {
- *ppvObject = static_cast<IMFSourceReaderCallback*>(this);
- } else if (riid == IID_IUnknown) {
- *ppvObject = static_cast<IUnknown*>(static_cast<IMFSourceReaderCallback*>(this));
- } else {
- *ppvObject = nullptr;
- return E_NOINTERFACE;
- }
- AddRef();
- return S_OK;
- }
-
- STDMETHODIMP_(ULONG) AddRef() override
- {
- return InterlockedIncrement(&m_cRef);
- }
-
- STDMETHODIMP_(ULONG) Release() override
- {
- LONG cRef = InterlockedDecrement(&m_cRef);
- if (cRef == 0) {
- delete this;
- }
- return cRef;
- }
-
//from IMFSourceReaderCallback
STDMETHODIMP OnReadSample(HRESULT status, DWORD, DWORD, LONGLONG timestamp, IMFSample *sample) override;
STDMETHODIMP OnFlush(DWORD) override;
@@ -101,22 +35,24 @@ public:
m_activeCamera = activeCamera;
}
private:
- LONG m_cRef;
+ // Destructor is not public. Caller should call Release.
+ ~CameraReaderCallback() override = default;
+
ActiveCamera *m_activeCamera = nullptr;
QMutex m_mutex;
};
-static QWindowsIUPointer<IMFSourceReader> createCameraReader(IMFMediaSource *mediaSource,
- const QWindowsIUPointer<CameraReaderCallback> &callback)
+static ComPtr<IMFSourceReader> createCameraReader(IMFMediaSource *mediaSource,
+ const ComPtr<CameraReaderCallback> &callback)
{
- QWindowsIUPointer<IMFSourceReader> sourceReader;
- QWindowsIUPointer<IMFAttributes> readerAttributes;
+ ComPtr<IMFSourceReader> sourceReader;
+ ComPtr<IMFAttributes> readerAttributes;
- HRESULT hr = MFCreateAttributes(readerAttributes.address(), 1);
+ HRESULT hr = MFCreateAttributes(readerAttributes.GetAddressOf(), 1);
if (SUCCEEDED(hr)) {
- hr = readerAttributes->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, callback.get());
+ hr = readerAttributes->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, callback.Get());
if (SUCCEEDED(hr)) {
- hr = MFCreateSourceReaderFromMediaSource(mediaSource, readerAttributes.get(), sourceReader.address());
+ hr = MFCreateSourceReaderFromMediaSource(mediaSource, readerAttributes.Get(), sourceReader.GetAddressOf());
if (SUCCEEDED(hr))
return sourceReader;
}
@@ -126,18 +62,18 @@ static QWindowsIUPointer<IMFSourceReader> createCameraReader(IMFMediaSource *med
return sourceReader;
}
-static QWindowsIUPointer<IMFMediaSource> createCameraSource(const QString &deviceId)
+static ComPtr<IMFMediaSource> createCameraSource(const QString &deviceId)
{
- QWindowsIUPointer<IMFMediaSource> mediaSource;
- QWindowsIUPointer<IMFAttributes> sourceAttributes;
- HRESULT hr = MFCreateAttributes(sourceAttributes.address(), 2);
+ ComPtr<IMFMediaSource> mediaSource;
+ ComPtr<IMFAttributes> sourceAttributes;
+ HRESULT hr = MFCreateAttributes(sourceAttributes.GetAddressOf(), 2);
if (SUCCEEDED(hr)) {
hr = sourceAttributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, QMM_MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);
if (SUCCEEDED(hr)) {
hr = sourceAttributes->SetString(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK,
reinterpret_cast<LPCWSTR>(deviceId.utf16()));
if (SUCCEEDED(hr)) {
- hr = MFCreateDeviceSource(sourceAttributes.get(), mediaSource.address());
+ hr = MFCreateDeviceSource(sourceAttributes.Get(), mediaSource.GetAddressOf());
if (SUCCEEDED(hr))
return mediaSource;
}
@@ -147,53 +83,68 @@ static QWindowsIUPointer<IMFMediaSource> createCameraSource(const QString &devic
return mediaSource;
}
-static int calculateVideoFrameStride(IMFSourceReader *sourceReader, qsizetype formatIndex, int width)
+static int calculateVideoFrameStride(IMFMediaType *videoType, int width)
{
- Q_ASSERT(sourceReader);
- QWindowsIUPointer<IMFMediaType> videoType;
- HRESULT hr = sourceReader->GetNativeMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM,
- formatIndex, videoType.address());
+ Q_ASSERT(videoType);
+
+ GUID subtype = GUID_NULL;
+ HRESULT hr = videoType->GetGUID(MF_MT_SUBTYPE, &subtype);
if (SUCCEEDED(hr)) {
- GUID subtype = GUID_NULL;
- hr = videoType->GetGUID(MF_MT_SUBTYPE, &subtype);
- if (SUCCEEDED(hr)) {
- LONG stride = 0;
- hr = MFGetStrideForBitmapInfoHeader(subtype.Data1, width, &stride);
- if (SUCCEEDED(hr))
- return int(stride);
- }
+ LONG stride = 0;
+ hr = MFGetStrideForBitmapInfoHeader(subtype.Data1, width, &stride);
+ if (SUCCEEDED(hr))
+ return int(qAbs(stride));
}
- qWarning() << "Failed to calculate video stride" << hr;
+ qWarning() << "Failed to calculate video stride" << errorString(hr);
return 0;
}
-static bool setCameraReaderFormat(IMFSourceReader *sourceReader, qsizetype formatIndex)
+static bool setCameraReaderFormat(IMFSourceReader *sourceReader, IMFMediaType *videoType)
{
Q_ASSERT(sourceReader);
+ Q_ASSERT(videoType);
- QWindowsIUPointer<IMFMediaType> videoType;
- HRESULT hr = sourceReader->GetNativeMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM,
- formatIndex, videoType.address());
- if (SUCCEEDED(hr)) {
- hr = sourceReader->SetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM,
- nullptr, videoType.get());
- if (SUCCEEDED(hr)) {
- return true;
- } else {
- qWarning() << "Failed to set video format" << hr << std::system_category().message(hr).c_str();
- }
- } else {
- qWarning() << "Failed to select video format at index" << formatIndex << hr << std::system_category().message(hr).c_str();
- }
+ HRESULT hr = sourceReader->SetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM, nullptr,
+ videoType);
+ if (FAILED(hr))
+ qWarning() << "Failed to set video format" << errorString(hr);
- return false;
+ return SUCCEEDED(hr);
+}
+
+static ComPtr<IMFMediaType> findVideoType(IMFSourceReader *reader,
+ const QCameraFormat &format)
+{
+ for (DWORD i = 0;; ++i) {
+ ComPtr<IMFMediaType> candidate;
+ HRESULT hr = reader->GetNativeMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM, i,
+ candidate.GetAddressOf());
+ if (FAILED(hr))
+ break;
+
+ GUID subtype = GUID_NULL;
+ if (FAILED(candidate->GetGUID(MF_MT_SUBTYPE, &subtype)))
+ continue;
+
+ if (format.pixelFormat() != pixelFormatFromMediaSubtype(subtype))
+ continue;
+
+ UINT32 width = 0u;
+ UINT32 height = 0u;
+ if (FAILED(MFGetAttributeSize(candidate.Get(), MF_MT_FRAME_SIZE, &width, &height)))
+ continue;
+
+ if (format.resolution() != QSize{ int(width), int(height) })
+ continue;
+
+ return candidate;
+ }
+ return {};
}
class ActiveCamera {
public:
- ActiveCamera() = delete;
-
static std::unique_ptr<ActiveCamera> create(QWindowsCamera &wc, const QCameraDevice &device, const QCameraFormat &format)
{
auto ac = std::unique_ptr<ActiveCamera>(new ActiveCamera(wc));
@@ -201,48 +152,47 @@ public:
if (!ac->m_source)
return {};
- ac->m_readerCallback = QWindowsIUPointer<CameraReaderCallback>(new CameraReaderCallback);
+ ac->m_readerCallback = makeComObject<CameraReaderCallback>();
ac->m_readerCallback->setActiveCamera(ac.get());
- ac->m_reader = createCameraReader(ac->m_source.get(), ac->m_readerCallback);
+ ac->m_reader = createCameraReader(ac->m_source.Get(), ac->m_readerCallback);
if (!ac->m_reader)
return {};
- qsizetype index = device.videoFormats().indexOf(format);
- if (index < 0)
- return {};
-
- if (!ac->setFormat(format, index))
+ if (!ac->setFormat(format))
return {};
return ac;
}
- bool setFormat(const QCameraFormat &format, int formatIndex)
+ bool setFormat(const QCameraFormat &format)
{
- m_reader->Flush(MF_SOURCE_READER_FIRST_VIDEO_STREAM);
- m_flushWait.acquire();
-
- if (!setCameraReaderFormat(m_reader.get(), formatIndex))
- return false;
-
- m_frameFormat = { format.resolution(), format.pixelFormat() };
- m_videoFrameStride = calculateVideoFrameStride(m_reader.get(), formatIndex, format.resolution().width());
+ flush();
+
+ auto videoType = findVideoType(m_reader.Get(), format);
+ if (videoType) {
+ if (setCameraReaderFormat(m_reader.Get(), videoType.Get())) {
+ m_frameFormat = { format.resolution(), format.pixelFormat() };
+ m_videoFrameStride =
+ calculateVideoFrameStride(videoType.Get(), format.resolution().width());
+ }
+ }
- m_reader->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, nullptr,
- nullptr, nullptr, nullptr);
+ m_reader->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, nullptr, nullptr, nullptr,
+ nullptr);
return true;
}
void onReadSample(HRESULT status, LONGLONG timestamp, IMFSample *sample)
{
if (FAILED(status)) {
- emit m_windowsCamera.error(int(status), std::system_category().message(status).c_str());
+ const std::string msg{ std::system_category().message(status) };
+ m_windowsCamera.updateError(QCamera::CameraError, QString::fromStdString(msg));
return;
}
if (sample) {
- QWindowsIUPointer<IMFMediaBuffer> mediaBuffer;
- if (SUCCEEDED(sample->ConvertToContiguousBuffer(mediaBuffer.address()))) {
+ ComPtr<IMFMediaBuffer> mediaBuffer;
+ if (SUCCEEDED(sample->ConvertToContiguousBuffer(mediaBuffer.GetAddressOf()))) {
DWORD bufLen = 0;
BYTE *buffer = nullptr;
@@ -274,21 +224,27 @@ public:
~ActiveCamera()
{
- m_reader->Flush(MF_SOURCE_READER_FIRST_VIDEO_STREAM);
- m_flushWait.acquire();
+ flush();
m_readerCallback->setActiveCamera(nullptr);
}
private:
explicit ActiveCamera(QWindowsCamera &wc) : m_windowsCamera(wc), m_flushWait(0) {};
+ void flush()
+ {
+ if (SUCCEEDED(m_reader->Flush(MF_SOURCE_READER_FIRST_VIDEO_STREAM))) {
+ m_flushWait.acquire();
+ }
+ }
+
QWindowsCamera &m_windowsCamera;
QSemaphore m_flushWait;
- QWindowsIUPointer<IMFMediaSource> m_source;
- QWindowsIUPointer<IMFSourceReader> m_reader;
- QWindowsIUPointer<CameraReaderCallback> m_readerCallback;
+ ComPtr<IMFMediaSource> m_source;
+ ComPtr<IMFSourceReader> m_reader;
+ ComPtr<CameraReaderCallback> m_readerCallback;
QVideoFrameFormat m_frameFormat;
int m_videoFrameStride = 0;
@@ -339,8 +295,8 @@ void QWindowsCamera::setActive(bool active)
activeChanged(true);
} else {
- emit activeChanged(false);
m_active.reset();
+ emit activeChanged(false);
}
}
@@ -357,11 +313,10 @@ void QWindowsCamera::setCamera(const QCameraDevice &camera)
bool QWindowsCamera::setCameraFormat(const QCameraFormat &format)
{
- qsizetype index = m_cameraDevice.videoFormats().indexOf(format);
- if (index < 0)
+ if (format.isNull())
return false;
- bool ok = m_active ? m_active->setFormat(format, index) : true;
+ bool ok = m_active ? m_active->setFormat(format) : true;
if (ok)
m_cameraFormat = format;