summaryrefslogtreecommitdiffstats
path: root/src/plugins/directshow/camera
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/directshow/camera')
-rw-r--r--src/plugins/directshow/camera/directshowcameraglobal.h3
-rw-r--r--src/plugins/directshow/camera/dscamerasession.cpp290
-rw-r--r--src/plugins/directshow/camera/dscamerasession.h13
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;