diff options
Diffstat (limited to 'src/plugins/directshow/camera')
-rw-r--r-- | src/plugins/directshow/camera/directshowcameraglobal.h | 3 | ||||
-rw-r--r-- | src/plugins/directshow/camera/dscamerasession.cpp | 290 | ||||
-rw-r--r-- | src/plugins/directshow/camera/dscamerasession.h | 13 |
3 files changed, 38 insertions, 268 deletions
diff --git a/src/plugins/directshow/camera/directshowcameraglobal.h b/src/plugins/directshow/camera/directshowcameraglobal.h index 75112a090..8df387b4a 100644 --- a/src/plugins/directshow/camera/directshowcameraglobal.h +++ b/src/plugins/directshow/camera/directshowcameraglobal.h @@ -44,9 +44,6 @@ #include <dshow.h> -DEFINE_GUID(MEDIASUBTYPE_I420, - 0x30323449,0x0000,0x0010,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71); - extern const GUID MEDIASUBTYPE_RGB24; extern const GUID MEDIASUBTYPE_RGB32; extern const GUID MEDIASUBTYPE_YUY2; diff --git a/src/plugins/directshow/camera/dscamerasession.cpp b/src/plugins/directshow/camera/dscamerasession.cpp index 5587b479c..40e54a94d 100644 --- a/src/plugins/directshow/camera/dscamerasession.cpp +++ b/src/plugins/directshow/camera/dscamerasession.cpp @@ -47,148 +47,13 @@ #include "dscamerasession.h" #include "dsvideorenderer.h" +#include "directshowsamplegrabber.h" #include "directshowcameraglobal.h" +#include "directshowmediatype.h" +#include "directshowutils.h" QT_BEGIN_NAMESPACE - -namespace { -// DirectShow helper implementation -void _CopyMediaType(AM_MEDIA_TYPE *pmtTarget, const AM_MEDIA_TYPE *pmtSource) -{ - *pmtTarget = *pmtSource; - if (pmtTarget->cbFormat != 0) { - pmtTarget->pbFormat = reinterpret_cast<BYTE *>(CoTaskMemAlloc(pmtTarget->cbFormat)); - if (pmtTarget->pbFormat) - memcpy(pmtTarget->pbFormat, pmtSource->pbFormat, pmtTarget->cbFormat); - } - if (pmtTarget->pUnk != NULL) { - // pUnk should not be used. - pmtTarget->pUnk->AddRef(); - } -} - -void _FreeMediaType(AM_MEDIA_TYPE& mt) -{ - if (mt.cbFormat != 0) { - CoTaskMemFree((PVOID)mt.pbFormat); - mt.cbFormat = 0; - mt.pbFormat = NULL; - } - if (mt.pUnk != NULL) { - // pUnk should not be used. - mt.pUnk->Release(); - mt.pUnk = NULL; - } -} -} // end namespace - -static HRESULT getPin(IBaseFilter *filter, PIN_DIRECTION pinDir, IPin **pin); - - -class SampleGrabberCallbackPrivate : public ISampleGrabberCB -{ -public: - explicit SampleGrabberCallbackPrivate(DSCameraSession *session) - : m_ref(1) - , m_session(session) - { } - - virtual ~SampleGrabberCallbackPrivate() { } - - STDMETHODIMP_(ULONG) AddRef() - { - return InterlockedIncrement(&m_ref); - } - - STDMETHODIMP_(ULONG) Release() - { - ULONG ref = InterlockedDecrement(&m_ref); - if (ref == 0) - delete this; - return ref; - } - - STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject) - { - if (NULL == ppvObject) - return E_POINTER; - if (riid == IID_IUnknown /*__uuidof(IUnknown) */ ) { - *ppvObject = static_cast<IUnknown*>(this); - return S_OK; - } - if (riid == IID_ISampleGrabberCB /*__uuidof(ISampleGrabberCB)*/ ) { - *ppvObject = static_cast<ISampleGrabberCB*>(this); - return S_OK; - } - return E_NOTIMPL; - } - - STDMETHODIMP SampleCB(double Time, IMediaSample *pSample) - { - Q_UNUSED(Time) - Q_UNUSED(pSample) - return E_NOTIMPL; - } - - STDMETHODIMP BufferCB(double time, BYTE *pBuffer, long bufferLen) - { - // We display frames as they arrive, the presentation time is - // irrelevant - Q_UNUSED(time); - - if (m_session) { - m_session->onFrameAvailable(reinterpret_cast<const char *>(pBuffer), - bufferLen); - } - - return S_OK; - } - -private: - ULONG m_ref; - DSCameraSession *m_session; -}; - -QVideoFrame::PixelFormat pixelFormatFromMediaSubtype(GUID uid) -{ - if (uid == MEDIASUBTYPE_ARGB32) - return QVideoFrame::Format_ARGB32; - else if (uid == MEDIASUBTYPE_RGB32) - return QVideoFrame::Format_RGB32; - else if (uid == MEDIASUBTYPE_RGB24) - return QVideoFrame::Format_RGB24; - else if (uid == MEDIASUBTYPE_RGB565) - return QVideoFrame::Format_RGB565; - else if (uid == MEDIASUBTYPE_RGB555) - return QVideoFrame::Format_RGB555; - else if (uid == MEDIASUBTYPE_AYUV) - return QVideoFrame::Format_AYUV444; - else if (uid == MEDIASUBTYPE_I420 || uid == MEDIASUBTYPE_IYUV) - return QVideoFrame::Format_YUV420P; - else if (uid == MEDIASUBTYPE_YV12) - return QVideoFrame::Format_YV12; - else if (uid == MEDIASUBTYPE_UYVY) - return QVideoFrame::Format_UYVY; - else if (uid == MEDIASUBTYPE_YUYV || uid == MEDIASUBTYPE_YUY2) - return QVideoFrame::Format_YUYV; - else if (uid == MEDIASUBTYPE_NV12) - return QVideoFrame::Format_NV12; - else if (uid == MEDIASUBTYPE_MJPG) - return QVideoFrame::Format_Jpeg; - else if (uid == MEDIASUBTYPE_IMC1) - return QVideoFrame::Format_IMC1; - else if (uid == MEDIASUBTYPE_IMC2) - return QVideoFrame::Format_IMC2; - else if (uid == MEDIASUBTYPE_IMC3) - return QVideoFrame::Format_IMC3; - else if (uid == MEDIASUBTYPE_IMC4) - return QVideoFrame::Format_IMC4; - else - return QVideoFrame::Format_Invalid; -} - - DSCameraSession::DSCameraSession(QObject *parent) : QObject(parent) , m_graphBuilder(Q_NULLPTR) @@ -196,7 +61,6 @@ DSCameraSession::DSCameraSession(QObject *parent) , m_sourceDeviceName(QLatin1String("default")) , m_sourceFilter(Q_NULLPTR) , m_needsHorizontalMirroring(false) - , m_previewFilter(Q_NULLPTR) , m_previewSampleGrabber(Q_NULLPTR) , m_nullRendererFilter(Q_NULLPTR) , m_previewStarted(false) @@ -207,8 +71,6 @@ DSCameraSession::DSCameraSession(QObject *parent) , m_currentImageId(-1) , m_status(QCamera::UnloadedStatus) { - ZeroMemory(&m_sourceFormat, sizeof(m_sourceFormat)); - connect(this, SIGNAL(statusChanged(QCamera::Status)), this, SLOT(updateReadyForCapture())); } @@ -497,14 +359,13 @@ bool DSCameraSession::unload() setStatus(QCamera::UnloadingStatus); + m_previewSampleGrabber->deleteLater(); + m_previewSampleGrabber = nullptr; + m_needsHorizontalMirroring = false; m_supportedViewfinderSettings.clear(); - for (AM_MEDIA_TYPE f : qAsConst(m_supportedFormats)) - _FreeMediaType(f); m_supportedFormats.clear(); SAFE_RELEASE(m_sourceFilter); - SAFE_RELEASE(m_previewSampleGrabber); - SAFE_RELEASE(m_previewFilter); SAFE_RELEASE(m_nullRendererFilter); SAFE_RELEASE(m_filterGraph); SAFE_RELEASE(m_graphBuilder); @@ -571,6 +432,9 @@ bool DSCameraSession::stopPreview() setStatus(QCamera::StoppingStatus); + if (m_previewSampleGrabber) + m_previewSampleGrabber->stop(); + IMediaControl* pControl = 0; HRESULT hr = m_filterGraph->QueryInterface(IID_IMediaControl, (void**)&pControl); if (FAILED(hr)) { @@ -587,8 +451,7 @@ bool DSCameraSession::stopPreview() disconnectGraph(); - _FreeMediaType(m_sourceFormat); - ZeroMemory(&m_sourceFormat, sizeof(m_sourceFormat)); + m_sourceFormat.clear(); m_previewStarted = false; setStatus(QCamera::LoadedStatus); @@ -646,12 +509,12 @@ int DSCameraSession::captureImage(const QString &fileName) return m_imageIdCounter; } -void DSCameraSession::onFrameAvailable(const char *frameData, long len) +void DSCameraSession::onFrameAvailable(double time, quint8 *buffer, long len) { // !!! Not called on the main thread - + Q_UNUSED(time); // Deep copy, the data might be modified or freed after the callback returns - QByteArray data(frameData, len); + QByteArray data(reinterpret_cast<const char *>(buffer), len); m_presentMutex.lock(); @@ -688,7 +551,7 @@ void DSCameraSession::presentFrame() m_presentMutex.unlock(); QImage captureImage; - int captureId; + const int captureId = m_currentImageId; m_captureMutex.lock(); @@ -705,8 +568,6 @@ void DSCameraSession::presentFrame() m_capturedFrame.unmap(); - captureId = m_currentImageId; - QtConcurrent::run(this, &DSCameraSession::saveCapturedImage, m_currentImageId, captureImage, m_imageCaptureFileName); @@ -737,8 +598,6 @@ void DSCameraSession::saveCapturedImage(int id, const QImage &image, const QStri bool DSCameraSession::createFilterGraph() { // Previously containered in <qedit.h>. - static const IID iID_ISampleGrabber = { 0x6B652FFF, 0x11FE, 0x4fce, { 0x92, 0xAD, 0x02, 0x66, 0xB5, 0xD7, 0xC7, 0x8F } }; - static const CLSID cLSID_SampleGrabber = { 0xC1F400A0, 0x3F08, 0x11d3, { 0x9F, 0x0B, 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37 } }; static const CLSID cLSID_NullRenderer = { 0xC1F400A4, 0x3F08, 0x11d3, { 0x9F, 0x0B, 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37 } }; HRESULT hr; @@ -840,26 +699,12 @@ bool DSCameraSession::createFilterGraph() } // Sample grabber filter - hr = CoCreateInstance(cLSID_SampleGrabber, NULL,CLSCTX_INPROC, - IID_IBaseFilter, (void**)&m_previewFilter); - if (FAILED(hr)) { - qWarning() << "failed to create sample grabber"; - goto failed; + if (!m_previewSampleGrabber) { + m_previewSampleGrabber = new DirectShowSampleGrabber; + connect(m_previewSampleGrabber, &DirectShowSampleGrabber::bufferAvailable, + this, &DSCameraSession::onFrameAvailable); } - hr = m_previewFilter->QueryInterface(iID_ISampleGrabber, (void**)&m_previewSampleGrabber); - if (FAILED(hr)) { - qWarning() << "failed to get sample grabber"; - goto failed; - } - - { - SampleGrabberCallbackPrivate *callback = new SampleGrabberCallbackPrivate(this); - m_previewSampleGrabber->SetCallback(callback, 1); - m_previewSampleGrabber->SetOneShot(FALSE); - m_previewSampleGrabber->SetBufferSamples(FALSE); - callback->Release(); - } // Null renderer. Input connected to the sample grabber's output. Simply // discard the samples it receives. @@ -877,8 +722,6 @@ bool DSCameraSession::createFilterGraph() failed: m_needsHorizontalMirroring = false; SAFE_RELEASE(m_sourceFilter); - SAFE_RELEASE(m_previewSampleGrabber); - SAFE_RELEASE(m_previewFilter); SAFE_RELEASE(m_nullRendererFilter); SAFE_RELEASE(m_filterGraph); SAFE_RELEASE(m_graphBuilder); @@ -910,11 +753,11 @@ bool DSCameraSession::configurePreviewFormat() m_actualViewfinderSettings = resolvedViewfinderSettings; - _CopyMediaType(&m_sourceFormat, &m_supportedFormats[settingsIndex]); + m_sourceFormat = m_supportedFormats[settingsIndex]; // Set frame rate. // We don't care about the minimumFrameRate, DirectShow only allows to set an // average frame rate, so set that to the maximumFrameRate. - VIDEOINFOHEADER *videoInfo = reinterpret_cast<VIDEOINFOHEADER*>(m_sourceFormat.pbFormat); + VIDEOINFOHEADER *videoInfo = reinterpret_cast<VIDEOINFOHEADER*>(m_sourceFormat->pbFormat); videoInfo->AvgTimePerFrame = 10000000 / resolvedViewfinderSettings.maximumFrameRate(); // We only support RGB32, if the capture source doesn't support @@ -955,16 +798,11 @@ bool DSCameraSession::configurePreviewFormat() } // Set sample grabber format (always RGB32) - AM_MEDIA_TYPE grabberFormat; - ZeroMemory(&grabberFormat, sizeof(grabberFormat)); - grabberFormat.majortype = MEDIATYPE_Video; - grabberFormat.subtype = MEDIASUBTYPE_RGB32; - grabberFormat.formattype = FORMAT_VideoInfo; - hr = m_previewSampleGrabber->SetMediaType(&grabberFormat); - if (FAILED(hr)) { - qWarning() << "Failed to set video format on grabber"; + static const AM_MEDIA_TYPE grabberFormat { MEDIATYPE_Video, MEDIASUBTYPE_RGB32, 0, 0, 0, FORMAT_VideoInfo, nullptr, 0, nullptr}; + if (!m_previewSampleGrabber->setMediaType(&grabberFormat)) return false; - } + + m_previewSampleGrabber->start(DirectShowSampleGrabber::CallbackMethod::BufferCB); return true; } @@ -1052,8 +890,7 @@ bool DSCameraSession::connectGraph() return false; } - hr = m_filterGraph->AddFilter(m_previewFilter, L"Sample Grabber"); - if (FAILED(hr)) { + if (FAILED(m_filterGraph->AddFilter(m_previewSampleGrabber->filter(), L"Sample Grabber"))) { qWarning() << "failed to add sample grabber to graph"; return false; } @@ -1066,7 +903,7 @@ bool DSCameraSession::connectGraph() hr = m_graphBuilder->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, m_sourceFilter, - m_previewFilter, + m_previewSampleGrabber->filter(), m_nullRendererFilter); if (FAILED(hr)) { qWarning() << "Graph failed to connect filters" << hr; @@ -1078,40 +915,10 @@ bool DSCameraSession::connectGraph() void DSCameraSession::disconnectGraph() { - IPin *pPin = 0; - HRESULT hr = getPin(m_sourceFilter, PINDIR_OUTPUT, &pPin); - if (SUCCEEDED(hr)) { - m_filterGraph->Disconnect(pPin); - pPin->Release(); - pPin = NULL; - } - - hr = getPin(m_previewFilter, PINDIR_INPUT, &pPin); - if (SUCCEEDED(hr)) { - m_filterGraph->Disconnect(pPin); - pPin->Release(); - pPin = NULL; - } - - hr = getPin(m_previewFilter, PINDIR_OUTPUT, &pPin); - if (SUCCEEDED(hr)) { - m_filterGraph->Disconnect(pPin); - pPin->Release(); - pPin = NULL; - } - - hr = getPin(m_nullRendererFilter, PINDIR_INPUT, &pPin); - if (SUCCEEDED(hr)) { - m_filterGraph->Disconnect(pPin); - pPin->Release(); - pPin = NULL; - } - // To avoid increasing the memory usage every time the graph is re-connected it's // important that all filters are released; also the ones added by the "Intelligent Connect". IEnumFilters *enumFilters = NULL; - hr = m_filterGraph->EnumFilters(&enumFilters); - if (SUCCEEDED(hr)) { + if (SUCCEEDED(m_filterGraph->EnumFilters(&enumFilters))) { IBaseFilter *filter = NULL; while (enumFilters->Next(1, &filter, NULL) == S_OK) { m_filterGraph->RemoveFilter(filter); @@ -1137,8 +944,6 @@ void DSCameraSession::updateSourceCapabilities() m_supportedViewfinderSettings.clear(); m_needsHorizontalMirroring = false; - for (AM_MEDIA_TYPE f : qAsConst(m_supportedFormats)) - _FreeMediaType(f); m_supportedFormats.clear(); m_imageProcessingParametersInfos.clear(); @@ -1150,8 +955,7 @@ void DSCameraSession::updateSourceCapabilities() qWarning() << "Failed to get the video control"; } else { IPin *pPin = 0; - hr = getPin(m_sourceFilter, PINDIR_OUTPUT, &pPin); - if (FAILED(hr)) { + if (!DirectShowUtils::getPin(m_sourceFilter, PINDIR_OUTPUT, &pPin, &hr)) { qWarning() << "Failed to get the pin for the video control"; } else { long supportedModes; @@ -1190,7 +994,7 @@ void DSCameraSession::updateSourceCapabilities() for (int iIndex = 0; iIndex < iCount; ++iIndex) { hr = pConfig->GetStreamCaps(iIndex, &pmt, reinterpret_cast<BYTE*>(&scc)); if (hr == S_OK) { - QVideoFrame::PixelFormat pixelFormat = pixelFormatFromMediaSubtype(pmt->subtype); + QVideoFrame::PixelFormat pixelFormat = DirectShowMediaType::pixelFormatFromType(pmt); if (pmt->majortype == MEDIATYPE_Video && pmt->formattype == FORMAT_VideoInfo @@ -1203,8 +1007,7 @@ void DSCameraSession::updateSourceCapabilities() if (pVideoControl) { IPin *pPin = 0; - hr = getPin(m_sourceFilter, PINDIR_OUTPUT, &pPin); - if (FAILED(hr)) { + if (!DirectShowUtils::getPin(m_sourceFilter, PINDIR_OUTPUT, &pPin, &hr)) { qWarning() << "Failed to get the pin for the video control"; } else { long listSize = 0; @@ -1237,15 +1040,12 @@ void DSCameraSession::updateSourceCapabilities() settings.setPixelFormat(pixelFormat); settings.setPixelAspectRatio(1, 1); m_supportedViewfinderSettings.append(settings); - - AM_MEDIA_TYPE format; - _CopyMediaType(&format, pmt); - m_supportedFormats.append(format); + m_supportedFormats.append(DirectShowMediaType(*pmt)); } } - _FreeMediaType(*pmt); + DirectShowMediaType::deleteType(pmt); } } @@ -1254,30 +1054,4 @@ void DSCameraSession::updateSourceCapabilities() updateImageProcessingParametersInfos(); } -HRESULT getPin(IBaseFilter *pFilter, PIN_DIRECTION PinDir, IPin **ppPin) -{ - *ppPin = 0; - IEnumPins *pEnum = 0; - IPin *pPin = 0; - - HRESULT hr = pFilter->EnumPins(&pEnum); - if (FAILED(hr)) { - return hr; - } - - pEnum->Reset(); - while (pEnum->Next(1, &pPin, NULL) == S_OK) { - PIN_DIRECTION ThisPinDir; - pPin->QueryDirection(&ThisPinDir); - if (ThisPinDir == PinDir) { - pEnum->Release(); - *ppPin = pPin; - return S_OK; - } - pPin->Release(); - } - pEnum->Release(); - return E_FAIL; -} - QT_END_NAMESPACE diff --git a/src/plugins/directshow/camera/dscamerasession.h b/src/plugins/directshow/camera/dscamerasession.h index 61b156d8a..37730736f 100644 --- a/src/plugins/directshow/camera/dscamerasession.h +++ b/src/plugins/directshow/camera/dscamerasession.h @@ -56,6 +56,7 @@ #include <dshow.h> #include <objbase.h> #include <initguid.h> +#include "directshowmediatype.h" #ifdef Q_CC_MSVC # pragma comment(lib, "strmiids.lib") # pragma comment(lib, "ole32.lib") @@ -71,11 +72,10 @@ #define __IDxtKey_INTERFACE_DEFINED__ struct ICaptureGraphBuilder2; -struct ISampleGrabber; QT_BEGIN_NAMESPACE -class SampleGrabberCallbackPrivate; +class DirectShowSampleGrabber; class DSCameraSession : public QObject { @@ -154,7 +154,7 @@ private: void setStatus(QCamera::Status status); - void onFrameAvailable(const char *frameData, long len); + void onFrameAvailable(double time, quint8 *buffer, long len); void saveCapturedImage(int id, const QImage &image, const QString &path); bool createFilterGraph(); @@ -182,14 +182,13 @@ private: QString m_sourceDeviceName; IBaseFilter* m_sourceFilter; bool m_needsHorizontalMirroring; - QList<AM_MEDIA_TYPE> m_supportedFormats; + QList<DirectShowMediaType> m_supportedFormats; QList<QCameraViewfinderSettings> m_supportedViewfinderSettings; - AM_MEDIA_TYPE m_sourceFormat; + DirectShowMediaType m_sourceFormat; QMap<QCameraImageProcessingControl::ProcessingParameter, ImageProcessingParameterInfo> m_imageProcessingParametersInfos; // Preview - IBaseFilter *m_previewFilter; - ISampleGrabber *m_previewSampleGrabber; + DirectShowSampleGrabber *m_previewSampleGrabber; IBaseFilter *m_nullRendererFilter; QVideoFrame m_currentFrame; bool m_previewStarted; |