diff options
Diffstat (limited to 'src/plugins/directshow/player')
18 files changed, 609 insertions, 2364 deletions
diff --git a/src/plugins/directshow/player/directshoweventloop.cpp b/src/plugins/directshow/player/directshoweventloop.cpp deleted file mode 100644 index 87f969e42..000000000 --- a/src/plugins/directshow/player/directshoweventloop.cpp +++ /dev/null @@ -1,148 +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 <directshoweventloop.h> - -#include <QtCore/qcoreapplication.h> -#include <QtCore/qcoreevent.h> - -class DirectShowPostedEvent -{ -public: - DirectShowPostedEvent(QObject *receiver, QEvent *event) - : receiver(receiver) - , event(event) - , next(0) - { - } - - ~DirectShowPostedEvent() - { - delete event; - } - - QObject *receiver; - QEvent *event; - DirectShowPostedEvent *next; -}; - -DirectShowEventLoop::DirectShowEventLoop(QObject *parent) - : QObject(parent) - , m_postsHead(0) - , m_postsTail(0) - , m_eventHandle(::CreateEvent(0, 0, 0, 0)) - , m_waitHandle(::CreateEvent(0, 0, 0, 0)) -{ -} - -DirectShowEventLoop::~DirectShowEventLoop() -{ - ::CloseHandle(m_eventHandle); - ::CloseHandle(m_waitHandle); - - for (DirectShowPostedEvent *post = m_postsHead; post; post = m_postsHead) { - m_postsHead = m_postsHead->next; - - delete post; - } -} - -void DirectShowEventLoop::wait(QMutex *mutex) -{ - ::ResetEvent(m_waitHandle); - - mutex->unlock(); - - HANDLE handles[] = { m_eventHandle, m_waitHandle }; - while (::WaitForMultipleObjects(2, handles, false, INFINITE) == WAIT_OBJECT_0) - processEvents(); - - mutex->lock(); -} - -void DirectShowEventLoop::wake() -{ - ::SetEvent(m_waitHandle); -} - -void DirectShowEventLoop::postEvent(QObject *receiver, QEvent *event) -{ - QMutexLocker locker(&m_mutex); - - DirectShowPostedEvent *post = new DirectShowPostedEvent(receiver, event); - - if (m_postsTail) - m_postsTail->next = post; - else - m_postsHead = post; - - m_postsTail = post; - - QCoreApplication::postEvent(this, new QEvent(QEvent::User)); - ::SetEvent(m_eventHandle); -} - -void DirectShowEventLoop::customEvent(QEvent *event) -{ - if (event->type() == QEvent::User) { - processEvents(); - } else { - QObject::customEvent(event); - } -} - -void DirectShowEventLoop::processEvents() -{ - QMutexLocker locker(&m_mutex); - - ::ResetEvent(m_eventHandle); - - while(m_postsHead) { - DirectShowPostedEvent *post = m_postsHead; - m_postsHead = m_postsHead->next; - - if (!m_postsHead) - m_postsTail = 0; - - locker.unlock(); - QCoreApplication::sendEvent(post->receiver, post->event); - delete post; - locker.relock(); - } -} diff --git a/src/plugins/directshow/player/directshoweventloop.h b/src/plugins/directshow/player/directshoweventloop.h deleted file mode 100644 index 09d986de7..000000000 --- a/src/plugins/directshow/player/directshoweventloop.h +++ /dev/null @@ -1,76 +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$ -** -****************************************************************************/ - -#ifndef DIRECTSHOWEVENTLOOP_H -#define DIRECTSHOWEVENTLOOP_H - -#include <QtCore/qmutex.h> -#include <QtCore/qobject.h> -#include <QtCore/qwaitcondition.h> - -#include <qt_windows.h> - -class DirectShowPostedEvent; - -class DirectShowEventLoop : public QObject -{ - Q_OBJECT -public: - DirectShowEventLoop(QObject *parent = 0); - ~DirectShowEventLoop(); - - void wait(QMutex *mutex); - void wake(); - - void postEvent(QObject *object, QEvent *event); - -protected: - void customEvent(QEvent *event); - -private: - void processEvents(); - - DirectShowPostedEvent *m_postsHead; - DirectShowPostedEvent *m_postsTail; - HANDLE m_eventHandle; - HANDLE m_waitHandle; - QMutex m_mutex; -}; - -#endif diff --git a/src/plugins/directshow/player/directshowglobal.h b/src/plugins/directshow/player/directshowglobal.h deleted file mode 100644 index f7890c52b..000000000 --- a/src/plugins/directshow/player/directshowglobal.h +++ /dev/null @@ -1,150 +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$ -** -****************************************************************************/ - -#ifndef DIRECTSHOWGLOBAL_H -#define DIRECTSHOWGLOBAL_H - -#include <dshow.h> - -#include <QtCore/qglobal.h> - -template <typename T> T *com_cast(IUnknown *unknown, const IID &iid) -{ - T *iface = 0; - return unknown && unknown->QueryInterface(iid, reinterpret_cast<void **>(&iface)) == S_OK - ? iface - : 0; -} - -template <typename T> T *com_new(const IID &clsid) -{ - T *object = 0; - return CoCreateInstance( - clsid, - NULL, - CLSCTX_INPROC_SERVER, - IID_PPV_ARGS(&object)) == S_OK - ? object - : 0; -} - -template <typename T> T *com_new(const IID &clsid, const IID &iid) -{ - T *object = 0; - return CoCreateInstance( - clsid, - NULL, - CLSCTX_INPROC_SERVER, - iid, - reinterpret_cast<void **>(&object)) == S_OK - ? object - : 0; -} - -#ifndef __IFilterGraph2_INTERFACE_DEFINED__ -#define __IFilterGraph2_INTERFACE_DEFINED__ -#define INTERFACE IFilterGraph2 -DECLARE_INTERFACE_(IFilterGraph2 ,IGraphBuilder) -{ - STDMETHOD(AddSourceFilterForMoniker)(THIS_ IMoniker *, IBindCtx *, LPCWSTR,IBaseFilter **) PURE; - STDMETHOD(ReconnectEx)(THIS_ IPin *, const AM_MEDIA_TYPE *) PURE; - STDMETHOD(RenderEx)(IPin *, DWORD, DWORD *) PURE; -}; -#undef INTERFACE -#endif - -#ifndef __IAMFilterMiscFlags_INTERFACE_DEFINED__ -#define __IAMFilterMiscFlags_INTERFACE_DEFINED__ -#define INTERFACE IAMFilterMiscFlags -DECLARE_INTERFACE_(IAMFilterMiscFlags ,IUnknown) -{ - STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; - STDMETHOD_(ULONG,AddRef)(THIS) PURE; - STDMETHOD_(ULONG,Release)(THIS) PURE; - STDMETHOD_(ULONG,GetMiscFlags)(THIS) PURE; -}; -#undef INTERFACE -#endif - -#ifndef __IFileSourceFilter_INTERFACE_DEFINED__ -#define __IFileSourceFilter_INTERFACE_DEFINED__ -#define INTERFACE IFileSourceFilter -DECLARE_INTERFACE_(IFileSourceFilter ,IUnknown) -{ - STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; - STDMETHOD_(ULONG,AddRef)(THIS) PURE; - STDMETHOD_(ULONG,Release)(THIS) PURE; - STDMETHOD(Load)(THIS_ LPCOLESTR, const AM_MEDIA_TYPE *) PURE; - STDMETHOD(GetCurFile)(THIS_ LPOLESTR *ppszFileName, AM_MEDIA_TYPE *) PURE; -}; -#undef INTERFACE -#endif - -#ifndef __IAMOpenProgress_INTERFACE_DEFINED__ -#define __IAMOpenProgress_INTERFACE_DEFINED__ -#undef INTERFACE -#define INTERFACE IAMOpenProgress -DECLARE_INTERFACE_(IAMOpenProgress ,IUnknown) -{ - STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; - STDMETHOD_(ULONG,AddRef)(THIS) PURE; - STDMETHOD_(ULONG,Release)(THIS) PURE; - STDMETHOD(QueryProgress)(THIS_ LONGLONG *, LONGLONG *) PURE; - STDMETHOD(AbortOperation)(THIS) PURE; -}; -#undef INTERFACE -#endif - -#ifndef __IFilterChain_INTERFACE_DEFINED__ -#define __IFilterChain_INTERFACE_DEFINED__ -#define INTERFACE IFilterChain -DECLARE_INTERFACE_(IFilterChain ,IUnknown) -{ - STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; - STDMETHOD_(ULONG,AddRef)(THIS) PURE; - STDMETHOD_(ULONG,Release)(THIS) PURE; - STDMETHOD(StartChain)(IBaseFilter *, IBaseFilter *) PURE; - STDMETHOD(PauseChain)(IBaseFilter *, IBaseFilter *) PURE; - STDMETHOD(StopChain)(IBaseFilter *, IBaseFilter *) PURE; - STDMETHOD(RemoveChain)(IBaseFilter *, IBaseFilter *) PURE; -}; -#undef INTERFACE -#endif - -#endif diff --git a/src/plugins/directshow/player/directshowiosource.cpp b/src/plugins/directshow/player/directshowiosource.cpp index 6dee14fb0..9e71f34d0 100644 --- a/src/plugins/directshow/player/directshowiosource.cpp +++ b/src/plugins/directshow/player/directshowiosource.cpp @@ -41,6 +41,7 @@ #include "directshowglobal.h" #include "directshowmediatype.h" +#include "directshowmediatypeenum.h" #include "directshowpinenum.h" #include <QtCore/qcoreapplication.h> @@ -64,8 +65,6 @@ DirectShowIOSource::DirectShowIOSource(DirectShowEventLoop *loop) , m_peerPin(0) , m_pinId(QLatin1String("Data")) { - QVector<AM_MEDIA_TYPE> mediaTypes; - AM_MEDIA_TYPE type = { MEDIATYPE_Stream, // majortype @@ -83,10 +82,8 @@ DirectShowIOSource::DirectShowIOSource(DirectShowEventLoop *loop) for (int i = 0; i < count; ++i) { type.subtype = directshow_subtypes[i]; - mediaTypes.append(type); + m_supportedMediaTypes.append(type); } - - setMediaTypes(mediaTypes); } DirectShowIOSource::~DirectShowIOSource() @@ -566,7 +563,7 @@ HRESULT DirectShowIOSource::EnumMediaTypes(IEnumMediaTypes **ppEnum) if (!ppEnum) { return E_POINTER; } else { - *ppEnum = createMediaTypeEnum(); + *ppEnum = new DirectShowMediaTypeEnum(m_supportedMediaTypes); return S_OK; } diff --git a/src/plugins/directshow/player/directshowiosource.h b/src/plugins/directshow/player/directshowiosource.h index bb90ba398..c2add6062 100644 --- a/src/plugins/directshow/player/directshowiosource.h +++ b/src/plugins/directshow/player/directshowiosource.h @@ -43,13 +43,11 @@ #include "directshowglobal.h" #include "directshowioreader.h" #include "directshowmediatype.h" -#include "directshowmediatypelist.h" #include <QtCore/qfile.h> class DirectShowIOSource - : public DirectShowMediaTypeList - , public IBaseFilter + : public IBaseFilter , public IAMFilterMiscFlags , public IPin { @@ -128,6 +126,7 @@ private: IMemAllocator *m_allocator; IPin *m_peerPin; DirectShowMediaType m_mediaType; + QList<DirectShowMediaType> m_supportedMediaTypes; QString m_filterName; const QString m_pinId; QMutex m_mutex; diff --git a/src/plugins/directshow/player/directshowmediatype.cpp b/src/plugins/directshow/player/directshowmediatype.cpp deleted file mode 100644 index cbe1753ae..000000000 --- a/src/plugins/directshow/player/directshowmediatype.cpp +++ /dev/null @@ -1,207 +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 "directshowmediatype.h" - -namespace -{ - struct TypeLookup - { - QVideoFrame::PixelFormat pixelFormat; - GUID mediaType; - }; - - static const TypeLookup qt_typeLookup[] = - { - { QVideoFrame::Format_RGB32, /*MEDIASUBTYPE_RGB32*/ {0xe436eb7e, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}} }, - { QVideoFrame::Format_BGR24, /*MEDIASUBTYPE_RGB24*/ {0xe436eb7d, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}} }, - { QVideoFrame::Format_RGB565, /*MEDIASUBTYPE_RGB565*/ {0xe436eb7b, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}} }, - { QVideoFrame::Format_RGB555, /*MEDIASUBTYPE_RGB555*/ {0xe436eb7c, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}} }, - { QVideoFrame::Format_AYUV444, /*MEDIASUBTYPE_AYUV*/ {0x56555941, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} }, - { QVideoFrame::Format_YUYV, /*MEDIASUBTYPE_YUY2*/ {0x32595559, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} }, - { QVideoFrame::Format_UYVY, /*MEDIASUBTYPE_UYVY*/ {0x59565955, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} }, - { QVideoFrame::Format_IMC1, /*MEDIASUBTYPE_IMC1*/ {0x31434D49, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} }, - { QVideoFrame::Format_IMC2, /*MEDIASUBTYPE_IMC2*/ {0x32434D49, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} }, - { QVideoFrame::Format_IMC3, /*MEDIASUBTYPE_IMC3*/ {0x33434D49, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} }, - { QVideoFrame::Format_IMC4, /*MEDIASUBTYPE_IMC4*/ {0x34434D49, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} }, - { QVideoFrame::Format_YV12, /*MEDIASUBTYPE_YV12*/ {0x32315659, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} }, - { QVideoFrame::Format_NV12, /*MEDIASUBTYPE_NV12*/ {0x3231564E, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} }, - { QVideoFrame::Format_YUV420P, /*MEDIASUBTYPE_IYUV*/ {0x56555949, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} } - }; -} - -void DirectShowMediaType::copy(AM_MEDIA_TYPE *target, const AM_MEDIA_TYPE &source) -{ - *target = source; - - if (source.cbFormat > 0) { - target->pbFormat = reinterpret_cast<PBYTE>(CoTaskMemAlloc(source.cbFormat)); - memcpy(target->pbFormat, source.pbFormat, source.cbFormat); - } - if (target->pUnk) - target->pUnk->AddRef(); -} - -void DirectShowMediaType::deleteType(AM_MEDIA_TYPE *type) -{ - freeData(type); - - CoTaskMemFree(type); -} - -void DirectShowMediaType::freeData(AM_MEDIA_TYPE *type) -{ - if (type->cbFormat > 0) - CoTaskMemFree(type->pbFormat); - - if (type->pUnk) - type->pUnk->Release(); -} - - -GUID DirectShowMediaType::convertPixelFormat(QVideoFrame::PixelFormat format) -{ - // MEDIASUBTYPE_None; - static const GUID none = { - 0xe436eb8e, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70} }; - - const int count = sizeof(qt_typeLookup) / sizeof(TypeLookup); - - for (int i = 0; i < count; ++i) - if (qt_typeLookup[i].pixelFormat == format) - return qt_typeLookup[i].mediaType; - return none; -} - -QVideoSurfaceFormat DirectShowMediaType::formatFromType(const AM_MEDIA_TYPE &type) -{ - const int count = sizeof(qt_typeLookup) / sizeof(TypeLookup); - - for (int i = 0; i < count; ++i) { - if (IsEqualGUID(qt_typeLookup[i].mediaType, type.subtype) && type.cbFormat > 0) { - if (IsEqualGUID(type.formattype, FORMAT_VideoInfo)) { - VIDEOINFOHEADER *header = reinterpret_cast<VIDEOINFOHEADER *>(type.pbFormat); - - QVideoSurfaceFormat format( - QSize(header->bmiHeader.biWidth, qAbs(header->bmiHeader.biHeight)), - qt_typeLookup[i].pixelFormat); - - if (header->AvgTimePerFrame > 0) - format.setFrameRate(10000 /header->AvgTimePerFrame); - - format.setScanLineDirection(scanLineDirection(format.pixelFormat(), header->bmiHeader)); - - return format; - } else if (IsEqualGUID(type.formattype, FORMAT_VideoInfo2)) { - VIDEOINFOHEADER2 *header = reinterpret_cast<VIDEOINFOHEADER2 *>(type.pbFormat); - - QVideoSurfaceFormat format( - QSize(header->bmiHeader.biWidth, qAbs(header->bmiHeader.biHeight)), - qt_typeLookup[i].pixelFormat); - - if (header->AvgTimePerFrame > 0) - format.setFrameRate(10000 / header->AvgTimePerFrame); - - format.setScanLineDirection(scanLineDirection(format.pixelFormat(), header->bmiHeader)); - - return format; - } - } - } - return QVideoSurfaceFormat(); -} - -#define PAD_TO_DWORD(x) (((x) + 3) & ~3) -int DirectShowMediaType::bytesPerLine(const QVideoSurfaceFormat &format) -{ - switch (format.pixelFormat()) { - // 32 bpp packed formats. - case QVideoFrame::Format_RGB32: - case QVideoFrame::Format_AYUV444: - return format.frameWidth() * 4; - // 24 bpp packed formats. - case QVideoFrame::Format_RGB24: - return PAD_TO_DWORD(format.frameWidth() * 3); - // 16 bpp packed formats. - case QVideoFrame::Format_RGB565: - case QVideoFrame::Format_RGB555: - case QVideoFrame::Format_YUYV: - case QVideoFrame::Format_UYVY: - return PAD_TO_DWORD(format.frameWidth() * 2); - // Planar formats. - case QVideoFrame::Format_IMC1: - case QVideoFrame::Format_IMC2: - case QVideoFrame::Format_IMC3: - case QVideoFrame::Format_IMC4: - case QVideoFrame::Format_YV12: - case QVideoFrame::Format_NV12: - case QVideoFrame::Format_YUV420P: - return PAD_TO_DWORD(format.frameWidth()); - default: - return 0; - } -} - -QVideoSurfaceFormat::Direction DirectShowMediaType::scanLineDirection(QVideoFrame::PixelFormat pixelFormat, const BITMAPINFOHEADER &bmiHeader) -{ - /* MSDN http://msdn.microsoft.com/en-us/library/windows/desktop/dd318229(v=vs.85).aspx */ - /* For uncompressed RGB bitmaps: - * if biHeight is positive, the bitmap is a bottom-up DIB with the origin at the lower left corner. - * If biHeight is negative, the bitmap is a top-down DIB with the origin at the upper left corner. - * - * For YUV bitmaps: - * the bitmap is always top-down, regardless of the sign of biHeight. - * Decoders should offer YUV formats with postive biHeight, but for backward compatibility they should accept YUV formats with either positive or negative biHeight. - * - * For compressed formats: - * biHeight must be positive, regardless of image orientation. - */ - switch (pixelFormat) - { - case QVideoFrame::Format_RGB32: - case QVideoFrame::Format_BGR24: - case QVideoFrame::Format_RGB565: - case QVideoFrame::Format_RGB555: - return bmiHeader.biHeight < 0 - ? QVideoSurfaceFormat::TopToBottom - : QVideoSurfaceFormat::BottomToTop; - default: - return QVideoSurfaceFormat::TopToBottom; - } -} diff --git a/src/plugins/directshow/player/directshowmediatype.h b/src/plugins/directshow/player/directshowmediatype.h deleted file mode 100644 index cf5ac73aa..000000000 --- a/src/plugins/directshow/player/directshowmediatype.h +++ /dev/null @@ -1,76 +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$ -** -****************************************************************************/ - -#ifndef DIRECTSHOWMEDIATYPE_H -#define DIRECTSHOWMEDIATYPE_H - -#include <dshow.h> - -#include <qvideosurfaceformat.h> - -#include <dvdmedia.h> - -class DirectShowMediaType : public AM_MEDIA_TYPE -{ -public: - DirectShowMediaType() { memset(this, 0, sizeof(DirectShowMediaType)); } - DirectShowMediaType(const AM_MEDIA_TYPE &type) { copy(this, type); } - DirectShowMediaType(const DirectShowMediaType &other) { copy(this, other); } - DirectShowMediaType &operator =(const AM_MEDIA_TYPE &type) { - freeData(this); copy(this, type); return *this; } - DirectShowMediaType &operator =(const DirectShowMediaType &other) { - freeData(this); copy(this, other); return *this; } - ~DirectShowMediaType() { freeData(this); } - - void clear() { freeData(this); memset(this, 0, sizeof(DirectShowMediaType)); } - - static void copy(AM_MEDIA_TYPE *target, const AM_MEDIA_TYPE &source); - static void freeData(AM_MEDIA_TYPE *type); - static void deleteType(AM_MEDIA_TYPE *type); - - static GUID convertPixelFormat(QVideoFrame::PixelFormat format); - static QVideoSurfaceFormat formatFromType(const AM_MEDIA_TYPE &type); - - static int bytesPerLine(const QVideoSurfaceFormat &format); - -private: - static QVideoSurfaceFormat::Direction scanLineDirection(QVideoFrame::PixelFormat pixelFormat, const BITMAPINFOHEADER &bmiHeader); -}; - -#endif diff --git a/src/plugins/directshow/player/directshowmediatypelist.cpp b/src/plugins/directshow/player/directshowmediatypelist.cpp deleted file mode 100644 index 8d5e572ca..000000000 --- a/src/plugins/directshow/player/directshowmediatypelist.cpp +++ /dev/null @@ -1,228 +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 "directshowmediatypelist.h" - -#include "directshowmediatype.h" -#include "videosurfacefilter.h" - - -class DirectShowMediaTypeEnum : public IEnumMediaTypes -{ -public: - DirectShowMediaTypeEnum(DirectShowMediaTypeList *list, int token, int index = 0); - virtual ~DirectShowMediaTypeEnum(); - - // IUnknown - HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); - ULONG STDMETHODCALLTYPE AddRef(); - ULONG STDMETHODCALLTYPE Release(); - - // IEnumMediaTypes - HRESULT STDMETHODCALLTYPE Next( - ULONG cMediaTypes, AM_MEDIA_TYPE **ppMediaTypes, ULONG *pcFetched); - HRESULT STDMETHODCALLTYPE Skip(ULONG cMediaTypes); - HRESULT STDMETHODCALLTYPE Reset(); - - HRESULT STDMETHODCALLTYPE Clone(IEnumMediaTypes **ppEnum); - -private: - LONG m_ref; - DirectShowMediaTypeList *m_list; - int m_mediaTypeToken; - int m_index; -}; - - -DirectShowMediaTypeEnum::DirectShowMediaTypeEnum( - DirectShowMediaTypeList *list, int token, int index) - : m_ref(1) - , m_list(list) - , m_mediaTypeToken(token) - , m_index(index) -{ - m_list->AddRef(); -} - -DirectShowMediaTypeEnum::~DirectShowMediaTypeEnum() -{ - m_list->Release(); -} - -HRESULT DirectShowMediaTypeEnum::QueryInterface(REFIID riid, void **ppvObject) -{ - if (!ppvObject) { - return E_POINTER; - } else if (riid == IID_IUnknown - || riid == IID_IEnumMediaTypes) { - *ppvObject = static_cast<IEnumMediaTypes *>(this); - } else { - *ppvObject = 0; - - return E_NOINTERFACE; - } - - AddRef(); - - return S_OK; -} - -ULONG DirectShowMediaTypeEnum::AddRef() -{ - return InterlockedIncrement(&m_ref); -} - -ULONG DirectShowMediaTypeEnum::Release() -{ - ULONG ref = InterlockedDecrement(&m_ref); - - if (ref == 0) { - delete this; - } - - return ref; -} - -HRESULT DirectShowMediaTypeEnum::Next( - ULONG cMediaTypes, AM_MEDIA_TYPE **ppMediaTypes, ULONG *pcFetched) -{ - return m_list->nextMediaType(m_mediaTypeToken, &m_index, cMediaTypes, ppMediaTypes, pcFetched); -} - -HRESULT DirectShowMediaTypeEnum::Skip(ULONG cMediaTypes) -{ - return m_list->skipMediaType(m_mediaTypeToken, &m_index, cMediaTypes); -} - -HRESULT DirectShowMediaTypeEnum::Reset() -{ - m_mediaTypeToken = m_list->currentMediaTypeToken(); - m_index = 0; - - return S_OK; -} - -HRESULT DirectShowMediaTypeEnum::Clone(IEnumMediaTypes **ppEnum) -{ - return m_list->cloneMediaType(m_mediaTypeToken, m_index, ppEnum); -} - - -DirectShowMediaTypeList::DirectShowMediaTypeList() - : m_mediaTypeToken(0) -{ -} - -DirectShowMediaTypeList::~DirectShowMediaTypeList() -{ -} - -IEnumMediaTypes *DirectShowMediaTypeList::createMediaTypeEnum() -{ - return new DirectShowMediaTypeEnum(this, m_mediaTypeToken, 0); -} - - -void DirectShowMediaTypeList::setMediaTypes(const QVector<AM_MEDIA_TYPE> &types) -{ - ++m_mediaTypeToken; - - m_mediaTypes = types; -} - - -int DirectShowMediaTypeList::currentMediaTypeToken() -{ - return m_mediaTypeToken; -} - -HRESULT DirectShowMediaTypeList::nextMediaType( - int token, int *index, ULONG count, AM_MEDIA_TYPE **types, ULONG *fetchedCount) -{ - if (!types || (count != 1 && !fetchedCount)) { - return E_POINTER; - } else if (m_mediaTypeToken != token) { - return VFW_E_ENUM_OUT_OF_SYNC; - } else { - int boundedCount = qBound<int>(0, count, m_mediaTypes.count() - *index); - - for (int i = 0; i < boundedCount; ++i, ++(*index)) { - types[i] = reinterpret_cast<AM_MEDIA_TYPE *>(CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE))); - - if (types[i]) { - DirectShowMediaType::copy(types[i], m_mediaTypes.at(*index)); - } else { - for (--i; i >= 0; --i) - CoTaskMemFree(types[i]); - - if (fetchedCount) - *fetchedCount = 0; - - return E_OUTOFMEMORY; - } - } - if (fetchedCount) - *fetchedCount = boundedCount; - - return boundedCount == int(count) ? S_OK : S_FALSE; - } -} - -HRESULT DirectShowMediaTypeList::skipMediaType(int token, int *index, ULONG count) -{ - if (m_mediaTypeToken != token) { - return VFW_E_ENUM_OUT_OF_SYNC; - } else { - *index = qMin<int>(*index + count, m_mediaTypes.size()); - - return *index < m_mediaTypes.size() ? S_OK : S_FALSE; - } -} - -HRESULT DirectShowMediaTypeList::cloneMediaType(int token, int index, IEnumMediaTypes **enumeration) -{ - if (m_mediaTypeToken != token) { - return VFW_E_ENUM_OUT_OF_SYNC; - } else { - *enumeration = new DirectShowMediaTypeEnum(this, token, index); - - return S_OK; - } -} - diff --git a/src/plugins/directshow/player/directshowmediatypelist.h b/src/plugins/directshow/player/directshowmediatypelist.h deleted file mode 100644 index c6dac0e9b..000000000 --- a/src/plugins/directshow/player/directshowmediatypelist.h +++ /dev/null @@ -1,68 +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$ -** -****************************************************************************/ - -#ifndef DIRECTSHOWMEDIATYPELIST_H -#define DIRECTSHOWMEDIATYPELIST_H - -#include <dshow.h> - -#include <QtCore/qvector.h> - -class DirectShowMediaTypeList : public IUnknown -{ -public: - DirectShowMediaTypeList(); - virtual ~DirectShowMediaTypeList(); - - IEnumMediaTypes *createMediaTypeEnum(); - - void setMediaTypes(const QVector<AM_MEDIA_TYPE> &types); - - virtual int currentMediaTypeToken(); - virtual HRESULT nextMediaType( - int token, int *index, ULONG count, AM_MEDIA_TYPE **types, ULONG *fetchedCount); - virtual HRESULT skipMediaType(int token, int *index, ULONG count); - virtual HRESULT cloneMediaType(int token, int index, IEnumMediaTypes **enumeration); - -private: - int m_mediaTypeToken; - QVector<AM_MEDIA_TYPE> m_mediaTypes; -}; - -#endif diff --git a/src/plugins/directshow/player/directshowpinenum.cpp b/src/plugins/directshow/player/directshowpinenum.cpp deleted file mode 100644 index 7ef986a26..000000000 --- a/src/plugins/directshow/player/directshowpinenum.cpp +++ /dev/null @@ -1,132 +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 "directshowpinenum.h" - - -DirectShowPinEnum::DirectShowPinEnum(const QList<IPin *> &pins) - : m_ref(1) - , m_pins(pins) - , m_index(0) -{ - for (IPin *pin : qAsConst(m_pins)) - pin->AddRef(); -} - -DirectShowPinEnum::~DirectShowPinEnum() -{ - for (IPin *pin : qAsConst(m_pins)) - pin->Release(); -} - -HRESULT DirectShowPinEnum::QueryInterface(REFIID riid, void **ppvObject) -{ - if (riid == IID_IUnknown - || riid == IID_IEnumPins) { - AddRef(); - - *ppvObject = static_cast<IEnumPins *>(this); - - return S_OK; - } else { - *ppvObject = 0; - - return E_NOINTERFACE; - } -} - -ULONG DirectShowPinEnum::AddRef() -{ - return InterlockedIncrement(&m_ref); -} - -ULONG DirectShowPinEnum::Release() -{ - ULONG ref = InterlockedDecrement(&m_ref); - - if (ref == 0) { - delete this; - } - - return ref; -} - -HRESULT DirectShowPinEnum::Next(ULONG cPins, IPin **ppPins, ULONG *pcFetched) -{ - if (ppPins && (pcFetched || cPins == 1)) { - ULONG count = qBound<ULONG>(0, cPins, m_pins.count() - m_index); - - for (ULONG i = 0; i < count; ++i, ++m_index) { - ppPins[i] = m_pins.at(m_index); - ppPins[i]->AddRef(); - } - - if (pcFetched) - *pcFetched = count; - - return count == cPins ? S_OK : S_FALSE; - } else { - return E_POINTER; - } -} - -HRESULT DirectShowPinEnum::Skip(ULONG cPins) -{ - m_index = qMin(int(m_index + cPins), m_pins.count()); - - return m_index < m_pins.count() ? S_OK : S_FALSE; -} - -HRESULT DirectShowPinEnum::Reset() -{ - m_index = 0; - - return S_OK; -} - -HRESULT DirectShowPinEnum::Clone(IEnumPins **ppEnum) -{ - if (ppEnum) { - *ppEnum = new DirectShowPinEnum(m_pins); - - return S_OK; - } else { - return E_POINTER; - } -} diff --git a/src/plugins/directshow/player/directshowpinenum.h b/src/plugins/directshow/player/directshowpinenum.h deleted file mode 100644 index 8859f49a5..000000000 --- a/src/plugins/directshow/player/directshowpinenum.h +++ /dev/null @@ -1,71 +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$ -** -****************************************************************************/ - -#ifndef DIRECTSHOWPINENUM_H -#define DIRECTSHOWPINENUM_H - -#include <dshow.h> - -#include <QtCore/qlist.h> - - -class DirectShowPinEnum : public IEnumPins -{ -public: - DirectShowPinEnum(const QList<IPin *> &pins); - virtual ~DirectShowPinEnum(); - - // IUnknown - HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); - ULONG STDMETHODCALLTYPE AddRef(); - ULONG STDMETHODCALLTYPE Release(); - - // IEnumPins - HRESULT STDMETHODCALLTYPE Next(ULONG cPins, IPin **ppPins, ULONG *pcFetched); - HRESULT STDMETHODCALLTYPE Skip(ULONG cPins); - HRESULT STDMETHODCALLTYPE Reset(); - HRESULT STDMETHODCALLTYPE Clone(IEnumPins **ppEnum); - -private: - LONG m_ref; - QList<IPin *> m_pins; - int m_index; -}; - -#endif diff --git a/src/plugins/directshow/player/directshowsamplescheduler.cpp b/src/plugins/directshow/player/directshowsamplescheduler.cpp deleted file mode 100644 index 0aa257f7f..000000000 --- a/src/plugins/directshow/player/directshowsamplescheduler.cpp +++ /dev/null @@ -1,435 +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 "directshowsamplescheduler.h" - -#include <QtCore/qcoreapplication.h> -#include <QtCore/qcoreevent.h> - -class DirectShowTimedSample -{ -public: - DirectShowTimedSample(IMediaSample *sample) - : m_next(0) - , m_sample(sample) - , m_cookie(0) - , m_lastSample(false) - { - m_sample->AddRef(); - } - - ~DirectShowTimedSample() - { - m_sample->Release(); - } - - IMediaSample *sample() const { return m_sample; } - - DirectShowTimedSample *nextSample() const { return m_next; } - void setNextSample(DirectShowTimedSample *sample) { Q_ASSERT(!m_next); m_next = sample; } - - DirectShowTimedSample *remove() { - DirectShowTimedSample *next = m_next; delete this; return next; } - - bool schedule(IReferenceClock *clock, REFERENCE_TIME startTime, HANDLE handle); - void unschedule(IReferenceClock *clock); - - bool isReady(IReferenceClock *clock) const; - - bool isLast() const { return m_lastSample; } - void setLast() { m_lastSample = true; } - -private: - DirectShowTimedSample *m_next; - IMediaSample *m_sample; - DWORD_PTR m_cookie; - bool m_lastSample; -}; - -bool DirectShowTimedSample::schedule( - IReferenceClock *clock, REFERENCE_TIME startTime, HANDLE handle) -{ - REFERENCE_TIME sampleStartTime; - REFERENCE_TIME sampleEndTime; - if (m_sample->GetTime(&sampleStartTime, &sampleEndTime) == S_OK) { - if (clock->AdviseTime( - startTime, sampleStartTime, reinterpret_cast<HEVENT>(handle), &m_cookie) == S_OK) { - return true; - } - } - return false; -} - -void DirectShowTimedSample::unschedule(IReferenceClock *clock) -{ - clock->Unadvise(m_cookie); -} - -bool DirectShowTimedSample::isReady(IReferenceClock *clock) const -{ - REFERENCE_TIME sampleStartTime; - REFERENCE_TIME sampleEndTime; - REFERENCE_TIME currentTime; - if (m_sample->GetTime(&sampleStartTime, &sampleEndTime) == S_OK) { - if (clock->GetTime(¤tTime) == S_OK) - return currentTime >= sampleStartTime; - } - return true; -} - -DirectShowSampleScheduler::DirectShowSampleScheduler(IUnknown *pin, QObject *parent) - : QObject(parent) - , m_pin(pin) - , m_clock(0) - , m_allocator(0) - , m_head(0) - , m_tail(0) - , m_maximumSamples(1) - , m_state(Stopped) - , m_startTime(0) - , m_timeoutEvent(::CreateEvent(0, 0, 0, 0)) - , m_flushEvent(::CreateEvent(0, 0, 0, 0)) -{ - m_semaphore.release(m_maximumSamples); -} - -DirectShowSampleScheduler::~DirectShowSampleScheduler() -{ - ::CloseHandle(m_timeoutEvent); - ::CloseHandle(m_flushEvent); - - Q_ASSERT(!m_clock); - Q_ASSERT(!m_allocator); -} - -HRESULT DirectShowSampleScheduler::QueryInterface(REFIID riid, void **ppvObject) -{ - return m_pin->QueryInterface(riid, ppvObject); -} - -ULONG DirectShowSampleScheduler::AddRef() -{ - return m_pin->AddRef(); -} - -ULONG DirectShowSampleScheduler::Release() -{ - return m_pin->Release(); -} - -// IMemInputPin -HRESULT DirectShowSampleScheduler::GetAllocator(IMemAllocator **ppAllocator) -{ - if (!ppAllocator) { - return E_POINTER; - } else { - QMutexLocker locker(&m_mutex); - - if (!m_allocator) { - return VFW_E_NO_ALLOCATOR; - } else { - *ppAllocator = m_allocator; - - return S_OK; - } - } -} - -HRESULT DirectShowSampleScheduler::NotifyAllocator(IMemAllocator *pAllocator, BOOL bReadOnly) -{ - Q_UNUSED(bReadOnly); - - HRESULT hr; - ALLOCATOR_PROPERTIES properties; - - if (!pAllocator) { - if (m_allocator) - m_allocator->Release(); - - m_allocator = 0; - - return S_OK; - } else if ((hr = pAllocator->GetProperties(&properties)) != S_OK) { - return hr; - } else { - if (properties.cBuffers == 1) { - ALLOCATOR_PROPERTIES actual; - - properties.cBuffers = 2; - if ((hr = pAllocator->SetProperties(&properties, &actual)) != S_OK) - return hr; - } - - QMutexLocker locker(&m_mutex); - - if (m_allocator) - m_allocator->Release(); - - m_allocator = pAllocator; - m_allocator->AddRef(); - - return S_OK; - } -} - -HRESULT DirectShowSampleScheduler::GetAllocatorRequirements(ALLOCATOR_PROPERTIES *pProps) -{ - if (!pProps) - return E_POINTER; - - pProps->cBuffers = 2; - - return S_OK; -} - -HRESULT DirectShowSampleScheduler::Receive(IMediaSample *pSample) -{ - if (!pSample) - return E_POINTER; - - m_semaphore.acquire(1); - - QMutexLocker locker(&m_mutex); - - if (m_state & Flushing) { - m_semaphore.release(1); - - return S_FALSE; - } else if (m_state == Stopped) { - m_semaphore.release(); - - return VFW_E_WRONG_STATE; - } else { - DirectShowTimedSample *timedSample = new DirectShowTimedSample(pSample); - - if (m_tail) - m_tail->setNextSample(timedSample); - else - m_head = timedSample; - - m_tail = timedSample; - - if (m_state == Running) { - if (!timedSample->schedule(m_clock, m_startTime, m_timeoutEvent)) { - // Timing information is unavailable, so schedule frames immediately. - QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest)); - } else { - locker.unlock(); - HANDLE handles[] = { m_flushEvent, m_timeoutEvent }; - DWORD result = ::WaitForMultipleObjects(2, handles, FALSE, INFINITE); - locker.relock(); - - if (result == WAIT_OBJECT_0 + 1) - QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest)); - } - } else if (m_tail == m_head) { - // If this is the first frame make it available. - QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest)); - - if (m_state == Paused) { - ::ResetEvent(m_timeoutEvent); - - locker.unlock(); - HANDLE handles[] = { m_flushEvent, m_timeoutEvent }; - ::WaitForMultipleObjects(2, handles, FALSE, INFINITE); - locker.relock(); - } - } - - return S_OK; - } -} - -HRESULT DirectShowSampleScheduler::ReceiveMultiple( - IMediaSample **pSamples, long nSamples, long *nSamplesProcessed) -{ - if (!pSamples || !nSamplesProcessed) - return E_POINTER; - - for (*nSamplesProcessed = 0; *nSamplesProcessed < nSamples; ++(*nSamplesProcessed)) { - HRESULT hr = Receive(pSamples[*nSamplesProcessed]); - - if (hr != S_OK) - return hr; - } - return S_OK; -} - -HRESULT DirectShowSampleScheduler::ReceiveCanBlock() -{ - return S_OK; -} - -void DirectShowSampleScheduler::run(REFERENCE_TIME startTime) -{ - QMutexLocker locker(&m_mutex); - - m_state = (m_state & Flushing) | Running; - m_startTime = startTime; - - for (DirectShowTimedSample *sample = m_head; sample; sample = sample->nextSample()) { - sample->schedule(m_clock, m_startTime, m_timeoutEvent); - } - - if (!(m_state & Flushing)) - ::ResetEvent(m_flushEvent); - - if (!m_head) - ::SetEvent(m_timeoutEvent); - -} - -void DirectShowSampleScheduler::pause() -{ - QMutexLocker locker(&m_mutex); - - m_state = (m_state & Flushing) | Paused; - - for (DirectShowTimedSample *sample = m_head; sample; sample = sample->nextSample()) - sample->unschedule(m_clock); - - if (!(m_state & Flushing)) - ::ResetEvent(m_flushEvent); -} - -void DirectShowSampleScheduler::stop() -{ - QMutexLocker locker(&m_mutex); - - m_state = m_state & Flushing; - - for (DirectShowTimedSample *sample = m_head; sample; sample = sample->remove()) { - sample->unschedule(m_clock); - - m_semaphore.release(1); - } - - m_head = 0; - m_tail = 0; - - ::SetEvent(m_flushEvent); -} - -void DirectShowSampleScheduler::setFlushing(bool flushing) -{ - QMutexLocker locker(&m_mutex); - - const bool isFlushing = m_state & Flushing; - - if (isFlushing != flushing) { - if (flushing) { - m_state |= Flushing; - - for (DirectShowTimedSample *sample = m_head; sample; sample = sample->remove()) { - sample->unschedule(m_clock); - - m_semaphore.release(1); - } - m_head = 0; - m_tail = 0; - - ::SetEvent(m_flushEvent); - } else { - m_state &= ~Flushing; - - if (m_state != Stopped) - ::ResetEvent(m_flushEvent); - } - } -} - -void DirectShowSampleScheduler::setClock(IReferenceClock *clock) -{ - QMutexLocker locker(&m_mutex); - - if (m_clock) - m_clock->Release(); - - m_clock = clock; - - if (m_clock) - m_clock->AddRef(); -} - -IMediaSample *DirectShowSampleScheduler::takeSample(bool *eos) -{ - QMutexLocker locker(&m_mutex); - - if (m_head && m_head->isReady(m_clock)) { - IMediaSample *sample = m_head->sample(); - sample->AddRef(); - - *eos = m_head->isLast(); - - m_head = m_head->remove(); - - if (!m_head) - m_tail = 0; - - m_semaphore.release(1); - - return sample; - } else { - return 0; - } -} - -bool DirectShowSampleScheduler::scheduleEndOfStream() -{ - QMutexLocker locker(&m_mutex); - - if (m_tail) { - m_tail->setLast(); - - return true; - } else { - return false; - } -} - -bool DirectShowSampleScheduler::event(QEvent *event) -{ - if (event->type() == QEvent::UpdateRequest) { - emit sampleReady(); - - return true; - } else { - return QObject::event(event); - } -} diff --git a/src/plugins/directshow/player/directshowsamplescheduler.h b/src/plugins/directshow/player/directshowsamplescheduler.h deleted file mode 100644 index 1670d23ed..000000000 --- a/src/plugins/directshow/player/directshowsamplescheduler.h +++ /dev/null @@ -1,115 +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$ -** -****************************************************************************/ - -#ifndef DIRECTSHOWSAMPLESCHEDULER_H -#define DIRECTSHOWSAMPLESCHEDULER_H - -#include <dshow.h> - -#include <QtCore/qmutex.h> -#include <QtCore/qobject.h> -#include <QtCore/qsemaphore.h> - -class DirectShowTimedSample; - -class DirectShowSampleScheduler : public QObject, public IMemInputPin -{ - Q_OBJECT -public: - - enum State - { - Stopped = 0x00, - Running = 0x01, - Paused = 0x02, - RunMask = 0x03, - Flushing = 0x04 - }; - - DirectShowSampleScheduler(IUnknown *pin, QObject *parent = 0); - ~DirectShowSampleScheduler(); - - // IUnknown - HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); - ULONG STDMETHODCALLTYPE AddRef(); - ULONG STDMETHODCALLTYPE Release(); - - // IMemInputPin - HRESULT STDMETHODCALLTYPE GetAllocator(IMemAllocator **ppAllocator); - HRESULT STDMETHODCALLTYPE NotifyAllocator(IMemAllocator *pAllocator, BOOL bReadOnly); - HRESULT STDMETHODCALLTYPE GetAllocatorRequirements(ALLOCATOR_PROPERTIES *pProps); - - HRESULT STDMETHODCALLTYPE Receive(IMediaSample *pSample); - HRESULT STDMETHODCALLTYPE ReceiveMultiple(IMediaSample **pSamples, long nSamples, long *nSamplesProcessed); - HRESULT STDMETHODCALLTYPE ReceiveCanBlock(); - - void run(REFERENCE_TIME startTime); - void pause(); - void stop(); - void setFlushing(bool flushing); - - IReferenceClock *clock() const { return m_clock; } - void setClock(IReferenceClock *clock); - - bool schedule(IMediaSample *sample); - bool scheduleEndOfStream(); - - IMediaSample *takeSample(bool *eos); - - bool event(QEvent *event); - -Q_SIGNALS: - void sampleReady(); - -private: - IUnknown *m_pin; - IReferenceClock *m_clock; - IMemAllocator *m_allocator; - DirectShowTimedSample *m_head; - DirectShowTimedSample *m_tail; - int m_maximumSamples; - int m_state; - REFERENCE_TIME m_startTime; - HANDLE m_timeoutEvent; - HANDLE m_flushEvent; - QSemaphore m_semaphore; - QMutex m_mutex; -}; - -#endif diff --git a/src/plugins/directshow/player/mediasamplevideobuffer.cpp b/src/plugins/directshow/player/mediasamplevideobuffer.cpp deleted file mode 100644 index 58b146a89..000000000 --- a/src/plugins/directshow/player/mediasamplevideobuffer.cpp +++ /dev/null @@ -1,84 +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 "mediasamplevideobuffer.h" - -MediaSampleVideoBuffer::MediaSampleVideoBuffer(IMediaSample *sample, int bytesPerLine) - : QAbstractVideoBuffer(NoHandle) - , m_sample(sample) - , m_bytesPerLine(bytesPerLine) - , m_mapMode(NotMapped) -{ - m_sample->AddRef(); -} - -MediaSampleVideoBuffer::~MediaSampleVideoBuffer() -{ - m_sample->Release(); -} - -uchar *MediaSampleVideoBuffer::map(MapMode mode, int *numBytes, int *bytesPerLine) -{ - if (m_mapMode == NotMapped && mode != NotMapped) { - if (numBytes) - *numBytes = m_sample->GetActualDataLength(); - - if (bytesPerLine) - *bytesPerLine = m_bytesPerLine; - - BYTE *bytes = 0; - - if (m_sample->GetPointer(&bytes) == S_OK) { - m_mapMode = mode; - - return reinterpret_cast<uchar *>(bytes); - } - } - return 0; -} - -void MediaSampleVideoBuffer::unmap() -{ - m_mapMode = NotMapped; -} - -QAbstractVideoBuffer::MapMode MediaSampleVideoBuffer::mapMode() const -{ - return m_mapMode; -} diff --git a/src/plugins/directshow/player/mediasamplevideobuffer.h b/src/plugins/directshow/player/mediasamplevideobuffer.h deleted file mode 100644 index 6ec1470c5..000000000 --- a/src/plugins/directshow/player/mediasamplevideobuffer.h +++ /dev/null @@ -1,67 +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$ -** -****************************************************************************/ - -#ifndef MEDIASAMPLEVIDEOBUFFER_H -#define MEDIASAMPLEVIDEOBUFFER_H - -#include <dshow.h> - -#include <qabstractvideobuffer.h> - -class MediaSampleVideoBuffer : public QAbstractVideoBuffer -{ -public: - MediaSampleVideoBuffer(IMediaSample *sample, int bytesPerLine); - ~MediaSampleVideoBuffer(); - - IMediaSample *sample() { return m_sample; } - - uchar *map(MapMode mode, int *numBytes, int *bytesPerLine); - void unmap(); - - MapMode mapMode() const; - -private: - IMediaSample *m_sample; - int m_bytesPerLine; - MapMode m_mapMode; -}; - - -#endif diff --git a/src/plugins/directshow/player/player.pri b/src/plugins/directshow/player/player.pri index 0bc9c6d0a..8b4bb70b7 100644 --- a/src/plugins/directshow/player/player.pri +++ b/src/plugins/directshow/player/player.pri @@ -8,35 +8,22 @@ qtHaveModule(widgets): QT += widgets DEFINES += QMEDIA_DIRECTSHOW_PLAYER HEADERS += \ - $$PWD/directshoweventloop.h \ - $$PWD/directshowglobal.h \ $$PWD/directshowioreader.h \ $$PWD/directshowiosource.h \ - $$PWD/directshowmediatype.h \ - $$PWD/directshowmediatypelist.h \ - $$PWD/directshowpinenum.h \ $$PWD/directshowplayercontrol.h \ $$PWD/directshowplayerservice.h \ - $$PWD/directshowsamplescheduler.h \ $$PWD/directshowvideorenderercontrol.h \ - $$PWD/mediasamplevideobuffer.h \ $$PWD/videosurfacefilter.h \ $$PWD/directshowaudioendpointcontrol.h \ $$PWD/directshowmetadatacontrol.h \ $$PWD/vmr9videowindowcontrol.h SOURCES += \ - $$PWD/directshoweventloop.cpp \ $$PWD/directshowioreader.cpp \ $$PWD/directshowiosource.cpp \ - $$PWD/directshowmediatype.cpp \ - $$PWD/directshowmediatypelist.cpp \ - $$PWD/directshowpinenum.cpp \ $$PWD/directshowplayercontrol.cpp \ $$PWD/directshowplayerservice.cpp \ - $$PWD/directshowsamplescheduler.cpp \ $$PWD/directshowvideorenderercontrol.cpp \ - $$PWD/mediasamplevideobuffer.cpp \ $$PWD/videosurfacefilter.cpp \ $$PWD/directshowaudioendpointcontrol.cpp \ $$PWD/directshowmetadatacontrol.cpp \ diff --git a/src/plugins/directshow/player/videosurfacefilter.cpp b/src/plugins/directshow/player/videosurfacefilter.cpp index b7b0d3aa8..4cb97be39 100644 --- a/src/plugins/directshow/player/videosurfacefilter.cpp +++ b/src/plugins/directshow/player/videosurfacefilter.cpp @@ -41,226 +41,220 @@ #include "directshoweventloop.h" #include "directshowglobal.h" -#include "directshowpinenum.h" -#include "mediasamplevideobuffer.h" +#include "directshowvideobuffer.h" -#include <QtCore/qcoreapplication.h> -#include <QtCore/qcoreevent.h> #include <QtCore/qthread.h> +#include <QtCore/qloggingcategory.h> #include <qabstractvideosurface.h> #include <initguid.h> +Q_LOGGING_CATEGORY(qLcRenderFilter, "qt.multimedia.plugins.directshow.renderfilter") + // { e23cad72-153d-406c-bf3f-4c4b523d96f2 } DEFINE_GUID(CLSID_VideoSurfaceFilter, 0xe23cad72, 0x153d, 0x406c, 0xbf, 0x3f, 0x4c, 0x4b, 0x52, 0x3d, 0x96, 0xf2); -VideoSurfaceFilter::VideoSurfaceFilter( - QAbstractVideoSurface *surface, DirectShowEventLoop *loop, QObject *parent) - : QObject(parent) - , m_ref(1) - , m_state(State_Stopped) - , m_surface(surface) - , m_loop(loop) - , m_graph(0) - , m_peerPin(0) - , m_bytesPerLine(0) - , m_startResult(S_OK) - , m_pinId(QString::fromLatin1("reference")) - , m_sampleScheduler(static_cast<IPin *>(this)) +class VideoSurfaceInputPin : public DirectShowInputPin { - connect(surface, SIGNAL(supportedFormatsChanged()), this, SLOT(supportedFormatsChanged())); - connect(&m_sampleScheduler, SIGNAL(sampleReady()), this, SLOT(sampleReady())); -} + DIRECTSHOW_OBJECT -VideoSurfaceFilter::~VideoSurfaceFilter() -{ - Q_ASSERT(m_ref == 0); -} +public: + VideoSurfaceInputPin(VideoSurfaceFilter *filter); -HRESULT VideoSurfaceFilter::QueryInterface(REFIID riid, void **ppvObject) -{ - // 2dd74950-a890-11d1-abe8-00a0c905f375 - static const GUID iid_IAmFilterMiscFlags = { - 0x2dd74950, 0xa890, 0x11d1, {0xab, 0xe8, 0x00, 0xa0, 0xc9, 0x05, 0xf3, 0x75} }; + // DirectShowPin + bool isMediaTypeSupported(const DirectShowMediaType *type); + bool setMediaType(const DirectShowMediaType *type); - if (!ppvObject) { - return E_POINTER; - } else if (riid == IID_IUnknown - || riid == IID_IPersist - || riid == IID_IMediaFilter - || riid == IID_IBaseFilter) { - *ppvObject = static_cast<IBaseFilter *>(this); - } else if (riid == iid_IAmFilterMiscFlags) { - *ppvObject = static_cast<IAMFilterMiscFlags *>(this); - } else if (riid == IID_IPin) { - *ppvObject = static_cast<IPin *>(this); - } else if (riid == IID_IMemInputPin) { - *ppvObject = static_cast<IMemInputPin *>(&m_sampleScheduler); - } else { - *ppvObject = 0; + HRESULT completeConnection(IPin *pin); + HRESULT connectionEnded(); - return E_NOINTERFACE; - } + // IPin + STDMETHODIMP ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt); + STDMETHODIMP Disconnect(); + STDMETHODIMP EndOfStream(); + STDMETHODIMP BeginFlush(); + STDMETHODIMP EndFlush(); - AddRef(); + // IMemInputPin + STDMETHODIMP GetAllocatorRequirements(ALLOCATOR_PROPERTIES *pProps); + STDMETHODIMP Receive(IMediaSample *pMediaSample); - return S_OK; +private: + VideoSurfaceFilter *m_videoSurfaceFilter; +}; + +VideoSurfaceInputPin::VideoSurfaceInputPin(VideoSurfaceFilter *filter) + : DirectShowInputPin(filter, QStringLiteral("Input")) + , m_videoSurfaceFilter(filter) +{ } -ULONG VideoSurfaceFilter::AddRef() +bool VideoSurfaceInputPin::isMediaTypeSupported(const DirectShowMediaType *type) { - return InterlockedIncrement(&m_ref); + return m_videoSurfaceFilter->isMediaTypeSupported(type); } -ULONG VideoSurfaceFilter::Release() +bool VideoSurfaceInputPin::setMediaType(const DirectShowMediaType *type) { - ULONG ref = InterlockedDecrement(&m_ref); - if (ref == 0) - delete this; + if (!DirectShowInputPin::setMediaType(type)) + return false; - return ref; + return m_videoSurfaceFilter->setMediaType(type); } -HRESULT VideoSurfaceFilter::GetClassID(CLSID *pClassID) +HRESULT VideoSurfaceInputPin::completeConnection(IPin *pin) { - *pClassID = CLSID_VideoSurfaceFilter; + HRESULT hr = DirectShowInputPin::completeConnection(pin); + if (FAILED(hr)) + return hr; - return S_OK; + return m_videoSurfaceFilter->completeConnection(pin); } -HRESULT VideoSurfaceFilter::Run(REFERENCE_TIME tStart) +HRESULT VideoSurfaceInputPin::connectionEnded() { - m_state = State_Running; - - m_sampleScheduler.run(tStart); + HRESULT hr = DirectShowInputPin::connectionEnded(); + if (FAILED(hr)) + return hr; - return S_OK; + return m_videoSurfaceFilter->connectionEnded(); } -HRESULT VideoSurfaceFilter::Pause() +HRESULT VideoSurfaceInputPin::ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt) { - m_state = State_Paused; - - m_sampleScheduler.pause(); + QMutexLocker lock(&m_videoSurfaceFilter->m_mutex); + return DirectShowInputPin::ReceiveConnection(pConnector, pmt); +} - return S_OK; +HRESULT VideoSurfaceInputPin::Disconnect() +{ + QMutexLocker lock(&m_videoSurfaceFilter->m_mutex); + return DirectShowInputPin::Disconnect(); } -HRESULT VideoSurfaceFilter::Stop() +HRESULT VideoSurfaceInputPin::EndOfStream() { - m_state = State_Stopped; + QMutexLocker lock(&m_videoSurfaceFilter->m_mutex); + QMutexLocker renderLock(&m_videoSurfaceFilter->m_renderMutex); - m_sampleScheduler.stop(); + HRESULT hr = DirectShowInputPin::EndOfStream(); + if (hr != S_OK) + return hr; - if (thread() == QThread::currentThread()) { - flush(); - } else { - QMutexLocker locker(&m_mutex); - m_loop->postEvent(this, new QEvent(QEvent::Type(FlushSurface))); - m_wait.wait(&m_mutex); + return m_videoSurfaceFilter->EndOfStream(); +} + +HRESULT VideoSurfaceInputPin::BeginFlush() +{ + QMutexLocker lock(&m_videoSurfaceFilter->m_mutex); + { + QMutexLocker renderLock(&m_videoSurfaceFilter->m_renderMutex); + DirectShowInputPin::BeginFlush(); + m_videoSurfaceFilter->BeginFlush(); } + m_videoSurfaceFilter->resetEOS(); return S_OK; } -HRESULT VideoSurfaceFilter::GetState(DWORD dwMilliSecsTimeout, FILTER_STATE *pState) +HRESULT VideoSurfaceInputPin::EndFlush() { - Q_UNUSED(dwMilliSecsTimeout) - if (!pState) - return E_POINTER; - - *pState = m_state; + QMutexLocker lock(&m_videoSurfaceFilter->m_mutex); + QMutexLocker renderLock(&m_videoSurfaceFilter->m_renderMutex); - return S_OK; + HRESULT hr = m_videoSurfaceFilter->EndFlush(); + if (SUCCEEDED(hr)) + hr = DirectShowInputPin::EndFlush(); + return hr; } -HRESULT VideoSurfaceFilter::SetSyncSource(IReferenceClock *pClock) +HRESULT VideoSurfaceInputPin::GetAllocatorRequirements(ALLOCATOR_PROPERTIES *pProps) { + if (!pProps) + return E_POINTER; - m_sampleScheduler.setClock(pClock); + // We need at least two allocated buffers, one for holding the frame currently being + // rendered and another one to decode the following frame at the same time. + pProps->cBuffers = 2; return S_OK; } -HRESULT VideoSurfaceFilter::GetSyncSource(IReferenceClock **ppClock) +HRESULT VideoSurfaceInputPin::Receive(IMediaSample *pMediaSample) { - if (!ppClock) { - return E_POINTER; - } else { - *ppClock = m_sampleScheduler.clock(); - - if (*ppClock) { - (*ppClock)->AddRef(); - - return S_OK; - } else { - return S_FALSE; + HRESULT hr = m_videoSurfaceFilter->Receive(pMediaSample); + if (FAILED(hr)) { + QMutexLocker locker(&m_videoSurfaceFilter->m_mutex); + if (m_videoSurfaceFilter->state() != State_Stopped && !m_flushing && !m_inErrorState) { + m_videoSurfaceFilter->NotifyEvent(EC_ERRORABORT, hr, 0); + { + QMutexLocker renderLocker(&m_videoSurfaceFilter->m_renderMutex); + if (m_videoSurfaceFilter->m_running && !m_videoSurfaceFilter->m_EOSDelivered) + m_videoSurfaceFilter->notifyEOS(); + } + m_inErrorState = true; } } + + return hr; } -HRESULT VideoSurfaceFilter::EnumPins(IEnumPins **ppEnum) -{ - if (ppEnum) { - *ppEnum = new DirectShowPinEnum(QList<IPin *>() << this); - return S_OK; - } else { - return E_POINTER; - } +VideoSurfaceFilter::VideoSurfaceFilter(QAbstractVideoSurface *surface, DirectShowEventLoop *loop, QObject *parent) + : QObject(parent) + , m_loop(loop) + , m_pin(NULL) + , m_surface(surface) + , m_bytesPerLine(0) + , m_surfaceStarted(false) + , m_renderMutex(QMutex::Recursive) + , m_running(false) + , m_pendingSample(NULL) + , m_pendingSampleEndTime(0) + , m_renderEvent(CreateEvent(NULL, FALSE, FALSE, NULL)) + , m_flushEvent(CreateEvent(NULL, TRUE, FALSE, NULL)) + , m_adviseCookie(0) + , m_EOS(false) + , m_EOSDelivered(false) + , m_EOSTimer(0) +{ + supportedFormatsChanged(); + connect(surface, &QAbstractVideoSurface::supportedFormatsChanged, + this, &VideoSurfaceFilter::supportedFormatsChanged); } -HRESULT VideoSurfaceFilter::FindPin(LPCWSTR pId, IPin **ppPin) +VideoSurfaceFilter::~VideoSurfaceFilter() { - if (!ppPin || !pId) { - return E_POINTER; - } else if (QString::fromWCharArray(pId) == m_pinId) { - AddRef(); + clearPendingSample(); - *ppPin = this; + if (m_pin) + m_pin->Release(); - return S_OK; - } else { - return VFW_E_NOT_FOUND; - } + CloseHandle(m_flushEvent); + CloseHandle(m_renderEvent); } -HRESULT VideoSurfaceFilter::JoinFilterGraph(IFilterGraph *pGraph, LPCWSTR pName) +HRESULT VideoSurfaceFilter::getInterface(const IID &riid, void **ppvObject) { - m_graph = pGraph; - m_name = QString::fromWCharArray(pName); - - return S_OK; + if (riid == IID_IAMFilterMiscFlags) + return GetInterface(static_cast<IAMFilterMiscFlags*>(this), ppvObject); + else + return DirectShowBaseFilter::getInterface(riid, ppvObject); } -HRESULT VideoSurfaceFilter::QueryFilterInfo(FILTER_INFO *pInfo) +QList<DirectShowPin *> VideoSurfaceFilter::pins() { - if (pInfo) { - QString name = m_name; - - if (name.length() >= MAX_FILTER_NAME) - name.truncate(MAX_FILTER_NAME - 1); - - int length = name.toWCharArray(pInfo->achName); - pInfo->achName[length] = '\0'; - - if (m_graph) - m_graph->AddRef(); - - pInfo->pGraph = m_graph; + if (!m_pin) + m_pin = new VideoSurfaceInputPin(this); - return S_OK; - } else { - return E_POINTER; - } + return QList<DirectShowPin *>() << m_pin; } -HRESULT VideoSurfaceFilter::QueryVendorInfo(LPWSTR *pVendorInfo) +HRESULT VideoSurfaceFilter::GetClassID(CLSID *pClassID) { - Q_UNUSED(pVendorInfo); - - return E_NOTIMPL; + *pClassID = CLSID_VideoSurfaceFilter; + return S_OK; } ULONG VideoSurfaceFilter::GetMiscFlags() @@ -268,388 +262,527 @@ ULONG VideoSurfaceFilter::GetMiscFlags() return AM_FILTER_MISC_FLAGS_IS_RENDERER; } - -HRESULT VideoSurfaceFilter::Connect(IPin *pReceivePin, const AM_MEDIA_TYPE *pmt) -{ - Q_UNUSED(pReceivePin) - Q_UNUSED(pmt) - // This is an input pin, you shouldn't be calling Connect on it. - return E_POINTER; -} - -HRESULT VideoSurfaceFilter::ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt) +void VideoSurfaceFilter::supportedFormatsChanged() { - if (!pConnector) { - return E_POINTER; - } else if (!pmt) { - return E_POINTER; - } else { - HRESULT hr; - QMutexLocker locker(&m_mutex); + QWriteLocker writeLocker(&m_typesLock); - if (m_peerPin) { - hr = VFW_E_ALREADY_CONNECTED; - } else if (pmt->majortype != MEDIATYPE_Video) { - hr = VFW_E_TYPE_NOT_ACCEPTED; - } else { - m_surfaceFormat = DirectShowMediaType::formatFromType(*pmt); - m_bytesPerLine = DirectShowMediaType::bytesPerLine(m_surfaceFormat); + qCDebug(qLcRenderFilter, "supportedFormatChanged"); - if (thread() == QThread::currentThread()) { - hr = start(); - } else { - m_loop->postEvent(this, new QEvent(QEvent::Type(StartSurface))); + m_supportedTypes.clear(); - m_wait.wait(&m_mutex); + const QList<QVideoFrame::PixelFormat> formats = m_surface->supportedPixelFormats(); + m_supportedTypes.reserve(formats.count()); - hr = m_startResult; - } + for (QVideoFrame::PixelFormat format : formats) { + GUID subtype = DirectShowMediaType::convertPixelFormat(format); + if (!IsEqualGUID(subtype, MEDIASUBTYPE_None)) { + qCDebug(qLcRenderFilter) << " " << format; + m_supportedTypes.append(subtype); } - if (hr == S_OK) { - m_peerPin = pConnector; - m_peerPin->AddRef(); + } +} - DirectShowMediaType::copy(&m_mediaType, *pmt); - } - return hr; +bool VideoSurfaceFilter::isMediaTypeSupported(const DirectShowMediaType *type) +{ + if (type->majortype != MEDIATYPE_Video || type->bFixedSizeSamples == FALSE) + return false; + + QReadLocker readLocker(&m_typesLock); + + for (const GUID &supportedType : m_supportedTypes) { + if (IsEqualGUID(supportedType, type->subtype)) + return true; } + + return false; } -HRESULT VideoSurfaceFilter::start() +bool VideoSurfaceFilter::setMediaType(const DirectShowMediaType *type) { - if (!m_surface->isFormatSupported(m_surfaceFormat)) { - return VFW_E_TYPE_NOT_ACCEPTED; + if (!type) { + qCDebug(qLcRenderFilter, "clear media type"); + m_surfaceFormat = QVideoSurfaceFormat(); + m_bytesPerLine = 0; + return true; + } else { + m_surfaceFormat = DirectShowMediaType::formatFromType(*type); + m_bytesPerLine = DirectShowMediaType::bytesPerLine(m_surfaceFormat); + qCDebug(qLcRenderFilter) << "setMediaType -->" << m_surfaceFormat; + return m_surfaceFormat.isValid(); } - if (!m_surface->start(m_surfaceFormat)) { +} + +HRESULT VideoSurfaceFilter::completeConnection(IPin *pin) +{ + Q_UNUSED(pin); + + qCDebug(qLcRenderFilter, "completeConnection"); + + if (!startSurface()) return VFW_E_TYPE_NOT_ACCEPTED; - } else { + else return S_OK; - } } -HRESULT VideoSurfaceFilter::Disconnect() +HRESULT VideoSurfaceFilter::connectionEnded() +{ + qCDebug(qLcRenderFilter, "connectionEnded"); + + stopSurface(); + + return S_OK; +} + +HRESULT VideoSurfaceFilter::Run(REFERENCE_TIME tStart) { QMutexLocker locker(&m_mutex); - if (!m_peerPin) - return S_FALSE; + if (m_state == State_Running) + return S_OK; - if (thread() == QThread::currentThread()) { - stop(); - } else { - m_loop->postEvent(this, new QEvent(QEvent::Type(StopSurface))); + qCDebug(qLcRenderFilter, "Run (start=%lli)", tStart); + + HRESULT hr = DirectShowBaseFilter::Run(tStart); + if (FAILED(hr)) + return hr; + + ResetEvent(m_flushEvent); - m_wait.wait(&m_mutex); + IMemAllocator *allocator; + if (SUCCEEDED(m_pin->GetAllocator(&allocator))) { + allocator->Commit(); + allocator->Release(); } - m_mediaType.clear(); + QMutexLocker renderLocker(&m_renderMutex); - m_sampleScheduler.NotifyAllocator(0, FALSE); + m_running = true; - m_peerPin->Release(); - m_peerPin = 0; + if (!m_pendingSample) + checkEOS(); + else if (!scheduleSample(m_pendingSample)) + SetEvent(m_renderEvent); // render immediately return S_OK; } -void VideoSurfaceFilter::stop() +HRESULT VideoSurfaceFilter::Pause() { - m_surface->stop(); -} + QMutexLocker locker(&m_mutex); -HRESULT VideoSurfaceFilter::ConnectedTo(IPin **ppPin) -{ - if (!ppPin) { - return E_POINTER; - } else { - QMutexLocker locker(&m_mutex); + if (m_state == State_Paused) + return S_OK; - if (!m_peerPin) { - return VFW_E_NOT_CONNECTED; - } else { - m_peerPin->AddRef(); + qCDebug(qLcRenderFilter, "Pause"); - *ppPin = m_peerPin; + HRESULT hr = DirectShowBaseFilter::Pause(); + if (FAILED(hr)) + return hr; - return S_OK; - } + m_renderMutex.lock(); + m_EOSDelivered = false; + m_running = false; + m_renderMutex.unlock(); + + resetEOSTimer(); + ResetEvent(m_flushEvent); + unscheduleSample(); + + IMemAllocator *allocator; + if (SUCCEEDED(m_pin->GetAllocator(&allocator))) { + allocator->Commit(); + allocator->Release(); } + + return S_OK; } -HRESULT VideoSurfaceFilter::ConnectionMediaType(AM_MEDIA_TYPE *pmt) +HRESULT VideoSurfaceFilter::Stop() { - if (!pmt) { - return E_POINTER; - } else { - QMutexLocker locker(&m_mutex); + QMutexLocker locker(&m_mutex); - if (!m_peerPin) { - return VFW_E_NOT_CONNECTED; - } else { - DirectShowMediaType::copy(pmt, m_mediaType); + if (m_state == State_Stopped) + return S_OK; - return S_OK; - } - } -} + qCDebug(qLcRenderFilter, "Stop"); -HRESULT VideoSurfaceFilter::QueryPinInfo(PIN_INFO *pInfo) -{ - if (!pInfo) { - return E_POINTER; - } else { - AddRef(); + DirectShowBaseFilter::Stop(); - pInfo->pFilter = this; - pInfo->dir = PINDIR_INPUT; + clearPendingSample(); - const int bytes = qMin(MAX_FILTER_NAME, (m_pinId.length() + 1) * 2); + m_renderMutex.lock(); + m_EOSDelivered = false; + m_running = false; + m_renderMutex.unlock(); - ::memcpy(pInfo->achName, m_pinId.utf16(), bytes); + SetEvent(m_flushEvent); + resetEOS(); + unscheduleSample(); + flushSurface(); - return S_OK; + IMemAllocator *allocator; + if (SUCCEEDED(m_pin->GetAllocator(&allocator))) { + allocator->Decommit(); + allocator->Release(); } + + return S_OK; } -HRESULT VideoSurfaceFilter::QueryId(LPWSTR *Id) +HRESULT VideoSurfaceFilter::EndOfStream() { - if (!Id) { - return E_POINTER; - } else { - const int bytes = (m_pinId.length() + 1) * 2; + QMutexLocker renderLocker(&m_renderMutex); - *Id = static_cast<LPWSTR>(::CoTaskMemAlloc(bytes)); + qCDebug(qLcRenderFilter, "EndOfStream"); - ::memcpy(*Id, m_pinId.utf16(), bytes); + m_EOS = true; - return S_OK; - } -} + if (!m_pendingSample && m_running) + checkEOS(); -HRESULT VideoSurfaceFilter::QueryAccept(const AM_MEDIA_TYPE *pmt) -{ - return !m_surface->isFormatSupported(DirectShowMediaType::formatFromType(*pmt)) - ? S_OK - : S_FALSE; + return S_OK; } -HRESULT VideoSurfaceFilter::EnumMediaTypes(IEnumMediaTypes **ppEnum) +HRESULT VideoSurfaceFilter::BeginFlush() { - if (!ppEnum) { - return E_POINTER; - } else { - QMutexLocker locker(&m_mutex); + qCDebug(qLcRenderFilter, "BeginFlush"); - *ppEnum = createMediaTypeEnum(); + SetEvent(m_flushEvent); + unscheduleSample(); + clearPendingSample(); - return S_OK; - } + return S_OK; } -HRESULT VideoSurfaceFilter::QueryInternalConnections(IPin **apPin, ULONG *nPin) +HRESULT VideoSurfaceFilter::EndFlush() { - Q_UNUSED(apPin); - Q_UNUSED(nPin); + qCDebug(qLcRenderFilter, "EndFlush"); - return E_NOTIMPL; + ResetEvent(m_flushEvent); + return S_OK; } -HRESULT VideoSurfaceFilter::EndOfStream() +HRESULT VideoSurfaceFilter::Receive(IMediaSample *pMediaSample) { - QMutexLocker locker(&m_mutex); + { + QMutexLocker locker(&m_mutex); - if (!m_sampleScheduler.scheduleEndOfStream()) { - if (IMediaEventSink *sink = com_cast<IMediaEventSink>(m_graph, IID_IMediaEventSink)) { - sink->Notify( - EC_COMPLETE, - S_OK, - reinterpret_cast<LONG_PTR>(static_cast<IBaseFilter *>(this))); - sink->Release(); + qCDebug(qLcRenderFilter, "Receive (sample=%p)", pMediaSample); + + HRESULT hr = m_pin->DirectShowInputPin::Receive(pMediaSample); + if (hr != S_OK) { + qCDebug(qLcRenderFilter, " can't receive sample (error %X)", uint(hr)); + return E_FAIL; } - } - return S_OK; -} + // If the format dynamically changed, the sample contains information about the new format. + // We need to reset the format and restart the QAbstractVideoSurface. + if (m_pin->currentSampleProperties()->pMediaType + && (!m_pin->setMediaType(reinterpret_cast<const DirectShowMediaType *>(m_pin->currentSampleProperties()->pMediaType)) + || !restartSurface())) { + qCWarning(qLcRenderFilter, " dynamic format change failed, aborting rendering"); + NotifyEvent(EC_ERRORABORT, VFW_E_TYPE_NOT_ACCEPTED, 0); + return VFW_E_INVALIDMEDIATYPE; + } -HRESULT VideoSurfaceFilter::BeginFlush() -{ - QMutexLocker locker(&m_mutex); + { + QMutexLocker locker(&m_renderMutex); - m_sampleScheduler.setFlushing(true); + if (m_pendingSample || m_EOS) + return E_UNEXPECTED; - if (thread() == QThread::currentThread()) { - flush(); - } else { - m_loop->postEvent(this, new QEvent(QEvent::Type(FlushSurface))); + if (m_running && !scheduleSample(pMediaSample)) { + qCWarning(qLcRenderFilter, " sample can't be scheduled, discarding it"); + return S_OK; + } + + m_pendingSample = pMediaSample; + m_pendingSample->AddRef(); + m_pendingSampleEndTime = m_pin->currentSampleProperties()->tStop; + } - m_wait.wait(&m_mutex); + if (m_state == State_Paused) // Render immediately + renderPendingSample(); } - return S_OK; -} + qCDebug(qLcRenderFilter, " waiting for render time"); -HRESULT VideoSurfaceFilter::EndFlush() -{ - QMutexLocker locker(&m_mutex); + // Wait for render time. The clock will wake us up whenever the time comes. + // It can also be interrupted by a flush, pause or stop. + HANDLE waitObjects[] = { m_flushEvent, m_renderEvent }; + DWORD result = WAIT_TIMEOUT; + while (result == WAIT_TIMEOUT) + result = WaitForMultipleObjects(2, waitObjects, FALSE, INFINITE); - m_sampleScheduler.setFlushing(false); + if (result == WAIT_OBJECT_0) { + // render interrupted (flush, pause, stop) + qCDebug(qLcRenderFilter, " rendering of sample %p interrupted", pMediaSample); + return S_OK; + } - return S_OK; -} + m_adviseCookie = 0; -void VideoSurfaceFilter::flush() -{ - m_surface->present(QVideoFrame()); + QMutexLocker locker(&m_mutex); - m_wait.wakeAll(); -} + // State might have changed just before the lock + if (m_state == State_Stopped) { + qCDebug(qLcRenderFilter, " state changed to Stopped, discarding sample (%p)", pMediaSample); + return S_OK; + } -HRESULT VideoSurfaceFilter::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) -{ - Q_UNUSED(tStart); - Q_UNUSED(tStop); - Q_UNUSED(dRate); + QMutexLocker renderLock(&m_renderMutex); + + // Flush or pause might have happened just before the lock + if (m_pendingSample && m_running) { + renderLock.unlock(); + renderPendingSample(); + renderLock.relock(); + } else { + qCDebug(qLcRenderFilter, " discarding sample (%p)", pMediaSample); + } + + clearPendingSample(); + checkEOS(); + ResetEvent(m_renderEvent); return S_OK; } -HRESULT VideoSurfaceFilter::QueryDirection(PIN_DIRECTION *pPinDir) +bool VideoSurfaceFilter::scheduleSample(IMediaSample *sample) { - if (!pPinDir) { - return E_POINTER; - } else { - *pPinDir = PINDIR_INPUT; + if (!sample) + return false; - return S_OK; + qCDebug(qLcRenderFilter, "scheduleSample (sample=%p)", sample); + + REFERENCE_TIME sampleStart, sampleEnd; + if (FAILED(sample->GetTime(&sampleStart, &sampleEnd)) || !m_clock) { + qCDebug(qLcRenderFilter, " render now"); + SetEvent(m_renderEvent); // Render immediately + return true; } -} -int VideoSurfaceFilter::currentMediaTypeToken() -{ - QMutexLocker locker(&m_mutex); + if (sampleEnd < sampleStart) { // incorrect times + qCWarning(qLcRenderFilter, " invalid sample times (start=%lli, end=%lli)", sampleStart, sampleEnd); + return false; + } + + HRESULT hr = m_clock->AdviseTime(m_startTime, sampleStart, (HEVENT)m_renderEvent, &m_adviseCookie); + if (FAILED(hr)) { + qCWarning(qLcRenderFilter, " clock failed to advise time (error=%X)", uint(hr)); + return false; + } - return DirectShowMediaTypeList::currentMediaTypeToken(); + return true; } -HRESULT VideoSurfaceFilter::nextMediaType( - int token, int *index, ULONG count, AM_MEDIA_TYPE **types, ULONG *fetchedCount) +void VideoSurfaceFilter::unscheduleSample() { - QMutexLocker locker(&m_mutex); - - return DirectShowMediaTypeList::nextMediaType(token, index, count, types, fetchedCount); + if (m_adviseCookie) { + qCDebug(qLcRenderFilter, "unscheduleSample"); + m_clock->Unadvise(m_adviseCookie); + m_adviseCookie = 0; + } + ResetEvent(m_renderEvent); } -HRESULT VideoSurfaceFilter::skipMediaType(int token, int *index, ULONG count) +void VideoSurfaceFilter::clearPendingSample() { - QMutexLocker locker(&m_mutex); + QMutexLocker locker(&m_renderMutex); + if (m_pendingSample) { + qCDebug(qLcRenderFilter, "clearPendingSample"); + m_pendingSample->Release(); + m_pendingSample = NULL; + } +} - return DirectShowMediaTypeList::skipMediaType(token, index, count); +void QT_WIN_CALLBACK EOSTimerCallback(UINT, UINT, DWORD_PTR dwUser, DWORD_PTR, DWORD_PTR) +{ + VideoSurfaceFilter *that = reinterpret_cast<VideoSurfaceFilter *>(dwUser); + that->onEOSTimerTimeout(); } -HRESULT VideoSurfaceFilter::cloneMediaType(int token, int index, IEnumMediaTypes **enumeration) +void VideoSurfaceFilter::onEOSTimerTimeout() { - QMutexLocker locker(&m_mutex); + QMutexLocker locker(&m_renderMutex); - return DirectShowMediaTypeList::cloneMediaType(token, index, enumeration); + if (m_EOSTimer) { + m_EOSTimer = 0; + checkEOS(); + } } -void VideoSurfaceFilter::customEvent(QEvent *event) +void VideoSurfaceFilter::checkEOS() { - const int type = event->type(); - if (type == StartSurface) { - QMutexLocker locker(&m_mutex); + QMutexLocker locker(&m_renderMutex); - m_startResult = start(); + if (!m_EOS || m_EOSDelivered || m_EOSTimer) + return; - m_wait.wakeAll(); - } else if (type == StopSurface) { - QMutexLocker locker(&m_mutex); + if (!m_clock) { + notifyEOS(); + return; + } - stop(); + REFERENCE_TIME eosTime = m_startTime + m_pendingSampleEndTime; + REFERENCE_TIME currentTime; + m_clock->GetTime(¤tTime); + LONG delay = LONG((eosTime - currentTime) / 10000); - m_wait.wakeAll(); - } else if (type == FlushSurface) { - QMutexLocker locker(&m_mutex); + if (delay < 1) { + notifyEOS(); + } else { + qCDebug(qLcRenderFilter, "will trigger EOS in %li", delay); - flush(); + m_EOSTimer = timeSetEvent(delay, + 1, + EOSTimerCallback, + reinterpret_cast<DWORD_PTR>(this), + TIME_ONESHOT | TIME_CALLBACK_FUNCTION | TIME_KILL_SYNCHRONOUS); - m_wait.wakeAll(); - } else { - QObject::customEvent(event); + if (!m_EOSTimer) { + qDebug("Error with timer"); + notifyEOS(); + } } } -void VideoSurfaceFilter::supportedFormatsChanged() +void VideoSurfaceFilter::notifyEOS() { - QMutexLocker locker(&m_mutex); + QMutexLocker locker(&m_renderMutex); - // MEDIASUBTYPE_None; - static const GUID none = { - 0xe436eb8e, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70} }; + if (!m_running) + return; - const QList<QVideoFrame::PixelFormat> formats = m_surface->supportedPixelFormats(); + qCDebug(qLcRenderFilter, "notifyEOS, delivering EC_COMPLETE event"); - QVector<AM_MEDIA_TYPE> mediaTypes; - mediaTypes.reserve(formats.count()); + m_EOSTimer = 0; + m_EOSDelivered = true; + NotifyEvent(EC_COMPLETE, S_OK, (LONG_PTR)(IBaseFilter *)this); +} - AM_MEDIA_TYPE type; - type.majortype = MEDIATYPE_Video; - type.bFixedSizeSamples = TRUE; - type.bTemporalCompression = FALSE; - type.lSampleSize = 0; - type.formattype = GUID_NULL; - type.pUnk = 0; - type.cbFormat = 0; - type.pbFormat = 0; +void VideoSurfaceFilter::resetEOS() +{ + resetEOSTimer(); - for (QVideoFrame::PixelFormat format : formats) { - type.subtype = DirectShowMediaType::convertPixelFormat(format); + QMutexLocker locker(&m_renderMutex); - if (type.subtype != none) - mediaTypes.append(type); - } + if (m_EOS) + qCDebug(qLcRenderFilter, "resetEOS (delivered=%s)", m_EOSDelivered ? "true" : "false"); - setMediaTypes(mediaTypes); + m_EOS = false; + m_EOSDelivered = false; + m_pendingSampleEndTime = 0; } -void VideoSurfaceFilter::sampleReady() +void VideoSurfaceFilter::resetEOSTimer() { - bool eos = false; + if (m_EOSTimer) { + timeKillEvent(m_EOSTimer); + m_EOSTimer = 0; + } +} - IMediaSample *sample = m_sampleScheduler.takeSample(&eos); +bool VideoSurfaceFilter::startSurface() +{ + if (QThread::currentThread() != thread()) { + m_loop->postEvent(this, new QEvent(QEvent::Type(StartSurface))); + m_waitSurface.wait(&m_mutex); + return m_surfaceStarted; + } else { + m_surfaceStarted = m_surface->start(m_surfaceFormat); + qCDebug(qLcRenderFilter, "startSurface %s", m_surfaceStarted ? "succeeded" : "failed"); + return m_surfaceStarted; + } +} - if (sample) { - QVideoFrame frame(new MediaSampleVideoBuffer(sample, m_bytesPerLine), - m_surfaceFormat.frameSize(), - m_surfaceFormat.pixelFormat()); +void VideoSurfaceFilter::stopSurface() +{ + if (!m_surfaceStarted) + return; - if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph, IID_IMediaSeeking)) { - LONGLONG position = 0; - seeking->GetCurrentPosition(&position); - seeking->Release(); + if (QThread::currentThread() != thread()) { + m_loop->postEvent(this, new QEvent(QEvent::Type(StopSurface))); + m_waitSurface.wait(&m_mutex); + } else { + qCDebug(qLcRenderFilter, "stopSurface"); + m_surface->stop(); + m_surfaceStarted = false; + } +} - frame.setStartTime(position * 0.1); +bool VideoSurfaceFilter::restartSurface() +{ + if (QThread::currentThread() != thread()) { + m_loop->postEvent(this, new QEvent(QEvent::Type(RestartSurface))); + m_waitSurface.wait(&m_mutex); + return m_surfaceStarted; + } else { + m_surface->stop(); + m_surfaceStarted = m_surface->start(m_surfaceFormat); + qCDebug(qLcRenderFilter, "restartSurface %s", m_surfaceStarted ? "succeeded" : "failed"); + return m_surfaceStarted; + } +} - REFERENCE_TIME startTime = -1; - REFERENCE_TIME endTime = -1; - if (sample->GetTime(&startTime, &endTime) == S_OK) - frame.setEndTime(frame.startTime() + (endTime - startTime) * 0.1); - } +void VideoSurfaceFilter::flushSurface() +{ + if (QThread::currentThread() != thread()) { + m_loop->postEvent(this, new QEvent(QEvent::Type(FlushSurface))); + m_waitSurface.wait(&m_mutex); + } else { + qCDebug(qLcRenderFilter, "flushSurface"); + m_surface->present(QVideoFrame()); + } +} - m_surface->present(frame); +void VideoSurfaceFilter::renderPendingSample() +{ + if (QThread::currentThread() != thread()) { + m_loop->postEvent(this, new QEvent(QEvent::Type(RenderSample))); + m_waitSurface.wait(&m_mutex); + } else { + QMutexLocker locker(&m_renderMutex); + if (!m_pendingSample) + return; - sample->Release(); + qCDebug(qLcRenderFilter, "presentSample (sample=%p)", m_pendingSample); - if (eos) { - if (IMediaEventSink *sink = com_cast<IMediaEventSink>(m_graph, IID_IMediaEventSink)) { - sink->Notify( - EC_COMPLETE, - S_OK, - reinterpret_cast<LONG_PTR>(static_cast<IBaseFilter *>(this))); - sink->Release(); - } - } + m_surface->present(QVideoFrame(new DirectShowVideoBuffer(m_pendingSample, m_bytesPerLine), + m_surfaceFormat.frameSize(), + m_surfaceFormat.pixelFormat())); } } +bool VideoSurfaceFilter::event(QEvent *e) +{ + if (e->type() == QEvent::Type(StartSurface)) { + QMutexLocker locker(&m_mutex); + startSurface(); + m_waitSurface.wakeAll(); + return true; + } else if (e->type() == QEvent::Type(StopSurface)) { + QMutexLocker locker(&m_mutex); + stopSurface(); + m_waitSurface.wakeAll(); + return true; + } else if (e->type() == QEvent::Type(RestartSurface)) { + QMutexLocker locker(&m_mutex); + restartSurface(); + m_waitSurface.wakeAll(); + return true; + } else if (e->type() == QEvent::Type(FlushSurface)) { + QMutexLocker locker(&m_mutex); + flushSurface(); + m_waitSurface.wakeAll(); + return true; + } else if (e->type() == QEvent::Type(RenderSample)) { + QMutexLocker locker(&m_mutex); + renderPendingSample(); + m_waitSurface.wakeAll(); + return true; + } + + return QObject::event(e); +} diff --git a/src/plugins/directshow/player/videosurfacefilter.h b/src/plugins/directshow/player/videosurfacefilter.h index 001e2804b..581e33c70 100644 --- a/src/plugins/directshow/player/videosurfacefilter.h +++ b/src/plugins/directshow/player/videosurfacefilter.h @@ -40,135 +40,121 @@ #ifndef VIDEOSURFACEFILTER_H #define VIDEOSURFACEFILTER_H -#include "directshowglobal.h" -#include "directshowmediatypelist.h" -#include "directshowsamplescheduler.h" -#include "directshowmediatype.h" +#include "directshowbasefilter.h" -#include <QtCore/qbasictimer.h> #include <QtCore/qcoreevent.h> #include <QtCore/qmutex.h> -#include <QtCore/qsemaphore.h> -#include <QtCore/qstring.h> -#include <QtCore/qwaitcondition.h> - -#include <dshow.h> +#include <qreadwritelock.h> +#include <qsemaphore.h> +#include <qwaitcondition.h> QT_BEGIN_NAMESPACE class QAbstractVideoSurface; QT_END_NAMESPACE class DirectShowEventLoop; +class VideoSurfaceInputPin; -class VideoSurfaceFilter - : public QObject - , public DirectShowMediaTypeList - , public IBaseFilter - , public IAMFilterMiscFlags - , public IPin +class VideoSurfaceFilter : public QObject + , public DirectShowBaseFilter + , public IAMFilterMiscFlags { Q_OBJECT + DIRECTSHOW_OBJECT public: - VideoSurfaceFilter( - QAbstractVideoSurface *surface, DirectShowEventLoop *loop, QObject *parent = 0); + VideoSurfaceFilter(QAbstractVideoSurface *surface, DirectShowEventLoop *loop, QObject *parent = 0); ~VideoSurfaceFilter(); - // IUnknown - HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); - ULONG STDMETHODCALLTYPE AddRef(); - ULONG STDMETHODCALLTYPE Release(); + // DirectShowObject + HRESULT getInterface(REFIID riid, void **ppvObject); + + // DirectShowBaseFilter + QList<DirectShowPin *> pins(); // IPersist - HRESULT STDMETHODCALLTYPE GetClassID(CLSID *pClassID); + STDMETHODIMP GetClassID(CLSID *pClassID); // IMediaFilter - HRESULT STDMETHODCALLTYPE Run(REFERENCE_TIME tStart); - HRESULT STDMETHODCALLTYPE Pause(); - HRESULT STDMETHODCALLTYPE Stop(); - - HRESULT STDMETHODCALLTYPE GetState(DWORD dwMilliSecsTimeout, FILTER_STATE *pState); - - HRESULT STDMETHODCALLTYPE SetSyncSource(IReferenceClock *pClock); - HRESULT STDMETHODCALLTYPE GetSyncSource(IReferenceClock **ppClock); - - // IBaseFilter - HRESULT STDMETHODCALLTYPE EnumPins(IEnumPins **ppEnum); - HRESULT STDMETHODCALLTYPE FindPin(LPCWSTR Id, IPin **ppPin); - - HRESULT STDMETHODCALLTYPE JoinFilterGraph(IFilterGraph *pGraph, LPCWSTR pName); - - HRESULT STDMETHODCALLTYPE QueryFilterInfo(FILTER_INFO *pInfo); - HRESULT STDMETHODCALLTYPE QueryVendorInfo(LPWSTR *pVendorInfo); + STDMETHODIMP Run(REFERENCE_TIME tStart); + STDMETHODIMP Pause(); + STDMETHODIMP Stop(); // IAMFilterMiscFlags - ULONG STDMETHODCALLTYPE GetMiscFlags(); + STDMETHODIMP_(ULONG) GetMiscFlags(); - // IPin - HRESULT STDMETHODCALLTYPE Connect(IPin *pReceivePin, const AM_MEDIA_TYPE *pmt); - HRESULT STDMETHODCALLTYPE ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt); - HRESULT STDMETHODCALLTYPE Disconnect(); - HRESULT STDMETHODCALLTYPE ConnectedTo(IPin **ppPin); + // DirectShowPin (delegate) + bool isMediaTypeSupported(const DirectShowMediaType *type); + bool setMediaType(const DirectShowMediaType *type); + HRESULT completeConnection(IPin *pin); + HRESULT connectionEnded(); - HRESULT STDMETHODCALLTYPE ConnectionMediaType(AM_MEDIA_TYPE *pmt); + // IPin (delegate) + HRESULT EndOfStream(); + HRESULT BeginFlush(); + HRESULT EndFlush(); - HRESULT STDMETHODCALLTYPE QueryPinInfo(PIN_INFO *pInfo); - HRESULT STDMETHODCALLTYPE QueryId(LPWSTR *Id); + // IMemInputPin (delegate) + HRESULT Receive(IMediaSample *pMediaSample); - HRESULT STDMETHODCALLTYPE QueryAccept(const AM_MEDIA_TYPE *pmt); +private Q_SLOTS: + void supportedFormatsChanged(); + void checkEOS(); - HRESULT STDMETHODCALLTYPE EnumMediaTypes(IEnumMediaTypes **ppEnum); +private: + enum Events { + StartSurface = QEvent::User, + StopSurface = QEvent::User + 1, + RestartSurface = QEvent::User + 2, + FlushSurface = QEvent::User + 3, + RenderSample = QEvent::User + 4 + }; + + bool event(QEvent *); - HRESULT STDMETHODCALLTYPE QueryInternalConnections(IPin **apPin, ULONG *nPin); + bool startSurface(); + void stopSurface(); + bool restartSurface(); + void flushSurface(); - HRESULT STDMETHODCALLTYPE EndOfStream(); + bool scheduleSample(IMediaSample *sample); + void unscheduleSample(); + void renderPendingSample(); + void clearPendingSample(); - HRESULT STDMETHODCALLTYPE BeginFlush(); - HRESULT STDMETHODCALLTYPE EndFlush(); + void notifyEOS(); + void resetEOS(); + void resetEOSTimer(); + void onEOSTimerTimeout(); - HRESULT STDMETHODCALLTYPE NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); + friend void QT_WIN_CALLBACK EOSTimerCallback(UINT, UINT, DWORD_PTR dwUser, DWORD_PTR, DWORD_PTR); - HRESULT STDMETHODCALLTYPE QueryDirection(PIN_DIRECTION *pPinDir); + QMutex m_mutex; - int currentMediaTypeToken(); - HRESULT nextMediaType( - int token, int *index, ULONG count, AM_MEDIA_TYPE **types, ULONG *fetchedCount); - HRESULT skipMediaType(int token, int *index, ULONG count); - HRESULT cloneMediaType(int token, int index, IEnumMediaTypes **enumeration); + DirectShowEventLoop *m_loop; + VideoSurfaceInputPin *m_pin; -protected: - void customEvent(QEvent *event); + QWaitCondition m_waitSurface; + QAbstractVideoSurface *m_surface; + QVideoSurfaceFormat m_surfaceFormat; + int m_bytesPerLine; + bool m_surfaceStarted; -private Q_SLOTS: - void supportedFormatsChanged(); - void sampleReady(); + QList<GUID> m_supportedTypes; + QReadWriteLock m_typesLock; -private: - HRESULT start(); - void stop(); - void flush(); + QMutex m_renderMutex; + bool m_running; + IMediaSample *m_pendingSample; + REFERENCE_TIME m_pendingSampleEndTime; + HANDLE m_renderEvent; + HANDLE m_flushEvent; + DWORD_PTR m_adviseCookie; - enum - { - StartSurface = QEvent::User, - StopSurface, - FlushSurface - }; + bool m_EOS; + bool m_EOSDelivered; + UINT m_EOSTimer; - LONG m_ref; - FILTER_STATE m_state; - QAbstractVideoSurface *m_surface; - DirectShowEventLoop *m_loop; - IFilterGraph *m_graph; - IPin *m_peerPin; - int m_bytesPerLine; - HRESULT m_startResult; - QString m_name; - QString m_pinId; - DirectShowMediaType m_mediaType; - QVideoSurfaceFormat m_surfaceFormat; - QMutex m_mutex; - QWaitCondition m_wait; - DirectShowSampleScheduler m_sampleScheduler; + friend class VideoSurfaceInputPin; }; #endif |