summaryrefslogtreecommitdiffstats
path: root/plugins/pluginDirectShow
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/pluginDirectShow')
-rw-r--r--plugins/pluginDirectShow/dllmain_dshow.cxx156
-rw-r--r--plugins/pluginDirectShow/internals/DSBaseCaptureGraph.h64
-rw-r--r--plugins/pluginDirectShow/internals/DSBufferWriter.h48
-rw-r--r--plugins/pluginDirectShow/internals/DSCaptureFormat.cxx60
-rw-r--r--plugins/pluginDirectShow/internals/DSCaptureFormat.h47
-rw-r--r--plugins/pluginDirectShow/internals/DSCaptureGraph.cxx436
-rw-r--r--plugins/pluginDirectShow/internals/DSCaptureGraph.h106
-rw-r--r--plugins/pluginDirectShow/internals/DSCaptureUtils.cxx377
-rw-r--r--plugins/pluginDirectShow/internals/DSCaptureUtils.h60
-rw-r--r--plugins/pluginDirectShow/internals/DSDibHelper.cxx80
-rw-r--r--plugins/pluginDirectShow/internals/DSDibHelper.h106
-rw-r--r--plugins/pluginDirectShow/internals/DSDisplay.cxx622
-rw-r--r--plugins/pluginDirectShow/internals/DSDisplay.h84
-rw-r--r--plugins/pluginDirectShow/internals/DSDisplayGraph.cxx345
-rw-r--r--plugins/pluginDirectShow/internals/DSDisplayGraph.h110
-rw-r--r--plugins/pluginDirectShow/internals/DSDisplayOverlay.VMR.cxx179
-rw-r--r--plugins/pluginDirectShow/internals/DSDisplayOverlay.VMR9.cxx207
-rw-r--r--plugins/pluginDirectShow/internals/DSDisplayOverlay.cxx67
-rw-r--r--plugins/pluginDirectShow/internals/DSDisplayOverlay.h68
-rw-r--r--plugins/pluginDirectShow/internals/DSFrameRateFilter.cxx120
-rw-r--r--plugins/pluginDirectShow/internals/DSFrameRateFilter.h64
-rw-r--r--plugins/pluginDirectShow/internals/DSGrabber.cxx292
-rw-r--r--plugins/pluginDirectShow/internals/DSGrabber.h92
-rw-r--r--plugins/pluginDirectShow/internals/DSOutputFilter.cxx113
-rw-r--r--plugins/pluginDirectShow/internals/DSOutputFilter.h112
-rw-r--r--plugins/pluginDirectShow/internals/DSOutputStream.cxx313
-rw-r--r--plugins/pluginDirectShow/internals/DSOutputStream.h90
-rw-r--r--plugins/pluginDirectShow/internals/DSPushSource.h496
-rw-r--r--plugins/pluginDirectShow/internals/DSPushSourceDesktop.cxx434
-rw-r--r--plugins/pluginDirectShow/internals/DSScreenCastGraph.cxx257
-rw-r--r--plugins/pluginDirectShow/internals/DSScreenCastGraph.h160
-rw-r--r--plugins/pluginDirectShow/internals/DSUtils.cxx365
-rw-r--r--plugins/pluginDirectShow/internals/DSUtils.h82
-rw-r--r--plugins/pluginDirectShow/internals/Resizer.cxx1192
-rw-r--r--plugins/pluginDirectShow/internals/Resizer.h76
-rw-r--r--plugins/pluginDirectShow/internals/VideoDisplayName.cxx37
-rw-r--r--plugins/pluginDirectShow/internals/VideoDisplayName.h43
-rw-r--r--plugins/pluginDirectShow/internals/VideoFrame.h107
-rw-r--r--plugins/pluginDirectShow/internals/VideoGrabberName.cxx37
-rw-r--r--plugins/pluginDirectShow/internals/VideoGrabberName.h43
-rw-r--r--plugins/pluginDirectShow/internals/wince/CPropertyBag.cxx108
-rw-r--r--plugins/pluginDirectShow/internals/wince/CPropertyBag.h43
-rw-r--r--plugins/pluginDirectShow/internals/wince/DSISampleGrabberCB.h30
-rw-r--r--plugins/pluginDirectShow/internals/wince/DSNullFilter.cxx56
-rw-r--r--plugins/pluginDirectShow/internals/wince/DSNullFilter.h40
-rw-r--r--plugins/pluginDirectShow/internals/wince/DSSampleGrabber.cxx197
-rw-r--r--plugins/pluginDirectShow/internals/wince/DSSampleGrabber.h73
-rw-r--r--plugins/pluginDirectShow/internals/wince/DSSampleGrabberUtils.h38
-rw-r--r--plugins/pluginDirectShow/pluginDirectShow.vcproj379
-rw-r--r--plugins/pluginDirectShow/plugin_dshow_config.h103
-rw-r--r--plugins/pluginDirectShow/plugin_screencast_dshow_producer.cxx273
-rw-r--r--plugins/pluginDirectShow/plugin_video_dshow_consumer.cxx1319
-rw-r--r--plugins/pluginDirectShow/plugin_video_dshow_producer.cxx276
-rw-r--r--plugins/pluginDirectShow/version.rc102
54 files changed, 10784 insertions, 0 deletions
diff --git a/plugins/pluginDirectShow/dllmain_dshow.cxx b/plugins/pluginDirectShow/dllmain_dshow.cxx
new file mode 100644
index 0000000..2b1eda8
--- /dev/null
+++ b/plugins/pluginDirectShow/dllmain_dshow.cxx
@@ -0,0 +1,156 @@
+/* Copyright (C) 2011-2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#include "plugin_dshow_config.h"
+
+#include "tinymedia/tmedia_producer.h"
+#include "tinymedia/tmedia_consumer.h"
+
+#include "tsk_plugin.h"
+#include "tsk_debug.h"
+
+#include "internals/DSUtils.h"
+
+#include <streams.h>
+
+#if !defined(ENABLE_SCREENCAST)
+# define ENABLE_SCREENCAST 0
+#endif /* ENABLE_SCREENCAST */
+
+PLUGIN_DSHOW_BEGIN_DECLS /* BEGIN */
+PLUGIN_DSHOW_API int __plugin_get_def_count();
+PLUGIN_DSHOW_API tsk_plugin_def_type_t __plugin_get_def_type_at(int index);
+PLUGIN_DSHOW_API tsk_plugin_def_media_type_t __plugin_get_def_media_type_at(int index);
+PLUGIN_DSHOW_API tsk_plugin_def_ptr_const_t __plugin_get_def_at(int index);
+PLUGIN_DSHOW_END_DECLS /* END */
+
+extern const tmedia_consumer_plugin_def_t *plugin_video_dshow_consumer_plugin_def_t;
+extern const tmedia_producer_plugin_def_t *plugin_video_dshow_producer_plugin_def_t;
+extern const tmedia_producer_plugin_def_t *plugin_screencast_dshow_producer_plugin_def_t;
+
+CFactoryTemplate g_Templates[]=
+{ { L""
+, NULL
+, NULL
+, NULL
+, NULL
+}
+};
+int g_cTemplates = sizeof(g_Templates)/sizeof(g_Templates[0]);
+
+#if !defined(_WIN32_WCE)
+BOOL APIENTRY DllMain( HMODULE hModule,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved
+ )
+{
+ switch (ul_reason_for_call)
+ {
+ case DLL_PROCESS_ATTACH:
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+ return TRUE;
+}
+#endif
+
+typedef enum PLUGIN_INDEX_E
+{
+ PLUGIN_INDEX_VIDEO_CONSUMER,
+ PLUGIN_INDEX_VIDEO_PRODUCER,
+#if 0
+ PLUGIN_INDEX_SCREENCAST_PRODUCER,
+#endif
+ PLUGIN_INDEX_COUNT
+}
+PLUGIN_INDEX_T;
+
+
+int __plugin_get_def_count()
+{
+ return PLUGIN_INDEX_COUNT;
+}
+
+tsk_plugin_def_type_t __plugin_get_def_type_at(int index)
+{
+ switch(index){
+ case PLUGIN_INDEX_VIDEO_CONSUMER:
+ return IsD3D9Supported() ? tsk_plugin_def_type_consumer : tsk_plugin_def_type_none;
+ case PLUGIN_INDEX_VIDEO_PRODUCER:
+#if ENABLE_SCREENCAST
+ case PLUGIN_INDEX_SCREENCAST_PRODUCER:
+#endif
+ return tsk_plugin_def_type_producer;
+ default:
+ {
+ TSK_DEBUG_ERROR("No plugin at index %d", index);
+ return tsk_plugin_def_type_none;
+ }
+ }
+}
+
+tsk_plugin_def_media_type_t __plugin_get_def_media_type_at(int index)
+{
+ switch(index){
+ case PLUGIN_INDEX_VIDEO_CONSUMER:
+ {
+ return IsD3D9Supported() ? tsk_plugin_def_media_type_video : tsk_plugin_def_media_type_none;
+ }
+ case PLUGIN_INDEX_VIDEO_PRODUCER:
+ {
+ return tsk_plugin_def_media_type_video;
+ }
+#if ENABLE_SCREENCAST
+ case PLUGIN_INDEX_SCREENCAST_PRODUCER:
+ {
+ return tsk_plugin_def_media_type_screencast;
+ }
+#endif
+ default:
+ {
+ TSK_DEBUG_ERROR("No plugin at index %d", index);
+ return tsk_plugin_def_media_type_none;
+ }
+ }
+}
+
+tsk_plugin_def_ptr_const_t __plugin_get_def_at(int index)
+{
+ switch(index){
+ case PLUGIN_INDEX_VIDEO_CONSUMER:
+ {
+ return IsD3D9Supported() ? plugin_video_dshow_consumer_plugin_def_t : tsk_null;
+ }
+ case PLUGIN_INDEX_VIDEO_PRODUCER:
+ {
+ return plugin_video_dshow_producer_plugin_def_t;
+ }
+#if ENABLE_SCREENCAST
+ case PLUGIN_INDEX_SCREENCAST_PRODUCER:
+ {
+ return plugin_screencast_dshow_producer_plugin_def_t;
+ }
+#endif
+ default:
+ {
+ TSK_DEBUG_ERROR("No plugin at index %d", index);
+ return tsk_null;
+ }
+ }
+}
diff --git a/plugins/pluginDirectShow/internals/DSBaseCaptureGraph.h b/plugins/pluginDirectShow/internals/DSBaseCaptureGraph.h
new file mode 100644
index 0000000..1817fb5
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/DSBaseCaptureGraph.h
@@ -0,0 +1,64 @@
+/* Copyright (C) 2014 Mamadou DIOP
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#ifndef PLUGIN_DSHOW_DSBASECAPTUREGRAPH_H
+#define PLUGIN_DSHOW_DSBASECAPTUREGRAPH_H
+
+#include "plugin_dshow_config.h"
+
+#include <vector>
+#include <control.h>
+#include "internals/DSCaptureFormat.h"
+
+#if defined(_WIN32_WCE)
+# include <internals/wince/DSSampleGrabber.h>
+# include <internals/wince/DSNullFilter.h>
+# include <internals/wince/DSISampleGrabberCB.h>
+#else
+# include <qedit.h>
+#endif
+
+class DSBaseCaptureGraph
+{
+public:
+#if defined(_WIN32_WCE)
+ DSBaseCaptureGraph(DSISampleGrabberCB* callback, HRESULT *hr) {}
+#else
+ DSBaseCaptureGraph(ISampleGrabberCB* callback, HRESULT *hr) {}
+#endif
+ virtual ~DSBaseCaptureGraph() {}
+
+ virtual std::vector<DSCaptureFormat> *getFormats() = 0;
+
+ virtual HRESULT setSource(const std::string &devicePath) = 0;
+ virtual HRESULT setParameters(DSCaptureFormat *format, int framerate) = 0;
+
+ virtual HRESULT connect() = 0;
+ virtual HRESULT disconnect() = 0;
+
+ virtual HRESULT start() = 0;
+ virtual HRESULT stop() = 0;
+ virtual HRESULT pause() = 0;
+ virtual bool isRunning() = 0;
+ virtual bool isPaused() = 0;
+
+ virtual std::string getDeviceId() const = 0;
+
+ virtual HRESULT getConnectedMediaType(AM_MEDIA_TYPE *mediaType) = 0;
+};
+
+#endif /* PLUGIN_DSHOW_DSBASECAPTUREGRAPH_H */
diff --git a/plugins/pluginDirectShow/internals/DSBufferWriter.h b/plugins/pluginDirectShow/internals/DSBufferWriter.h
new file mode 100644
index 0000000..dbe1484
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/DSBufferWriter.h
@@ -0,0 +1,48 @@
+/* Copyright (C) 2011-2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#ifndef PLUGIN_DSHOW_DSBUFFERWRITTER_H
+#define PLUGIN_DSHOW_DSBUFFERWRITTER_H
+/*
+// TODO: do it only once
+#if !defined(TDSHOW_DEFINE_GUID) && !defined(_WIN32_WCE)
+#define TDSHOW_DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+ EXTERN_C const GUID DECLSPEC_SELECTANY name \
+ = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
+#elif !defined(TDSHOW_DEFINE_GUID) && defined(_WIN32_WCE)
+#define TDSHOW_DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+ EXTERN_C const GUID __declspec(selectany) name \
+ = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
+#endif
+
+// {27AD9929-E4E7-423b-8BDD-8AF5AC894DE0}
+TDSHOW_DEFINE_GUID(IID_DSBufferWriter,
+ 0x27ad9929, 0xe4e7, 0x423b, 0x8b, 0xdd, 0x8a, 0xf5, 0xac, 0x89, 0x4d, 0xe0);
+ */
+
+
+class DSBufferWriter
+#ifndef _WIN32_WCE
+ : public IUnknown
+#endif
+{
+public:
+ virtual void setBuffer (void* pBuffer, int size) = 0;
+ virtual HRESULT setImageFormat(UINT width, UINT height/*, GUID subType, UINT fps*/) = 0;
+};
+
+#endif
diff --git a/plugins/pluginDirectShow/internals/DSCaptureFormat.cxx b/plugins/pluginDirectShow/internals/DSCaptureFormat.cxx
new file mode 100644
index 0000000..378a215
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/DSCaptureFormat.cxx
@@ -0,0 +1,60 @@
+/* Copyright (C) 2011-2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#include "internals/DSCaptureFormat.h"
+#include <uuids.h>
+
+
+int DSCaptureFormat::getMatchScore(int w, int h)
+{
+ int factor;
+
+ if ((w == width) && (h = height)){
+ factor = 100;
+ }
+ else if ((w > this->width) && (h > this->height)){
+ factor = 0;
+ }
+ else{
+ factor = (50 * w) / this->width + (50 * h) / this->height;
+ }
+
+ if (isRGB()){
+ factor *= 2;
+ }
+
+ return factor;
+}
+
+bool DSCaptureFormat::isRGB()
+{
+ // Order used is optimized for most used RGB types
+ if (IsEqualGUID(this->chroma, MEDIASUBTYPE_RGB32)) return true;
+ if (IsEqualGUID(this->chroma, MEDIASUBTYPE_RGB24)) return true;
+ if (IsEqualGUID(this->chroma, MEDIASUBTYPE_RGB565)) return true;
+ if (IsEqualGUID(this->chroma, MEDIASUBTYPE_RGB555)) return true;
+ if (IsEqualGUID(this->chroma, MEDIASUBTYPE_RGB8)) return true;
+ if (IsEqualGUID(this->chroma, MEDIASUBTYPE_RGB4)) return true;
+ if (IsEqualGUID(this->chroma, MEDIASUBTYPE_RGB1)) return true;
+#ifndef _WIN32_WCE
+ if (IsEqualGUID(this->chroma, MEDIASUBTYPE_ARGB32)) return true;
+ if (IsEqualGUID(this->chroma, MEDIASUBTYPE_ARGB4444)) return true;
+ if (IsEqualGUID(this->chroma, MEDIASUBTYPE_ARGB1555)) return true;
+#endif
+
+ return false;
+}
diff --git a/plugins/pluginDirectShow/internals/DSCaptureFormat.h b/plugins/pluginDirectShow/internals/DSCaptureFormat.h
new file mode 100644
index 0000000..5e1cabb
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/DSCaptureFormat.h
@@ -0,0 +1,47 @@
+/* Copyright (C) 2011-2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#ifndef PLUGIN_DSHOW_DSCAPTUREFORMAT_H
+#define PLUGIN_DSHOW_DSCAPTUREFORMAT_H
+
+#include "plugin_dshow_config.h"
+#include <strmif.h>
+
+
+class DSCaptureFormat
+{
+public:
+ DSCaptureFormat(int w, int h, int f, GUID c) : width(w), height(h), fps(f), chroma(c) {};
+ virtual ~DSCaptureFormat() {};
+
+ int getWidth() { return this->width; };
+ int getHeight() { return this->height; };
+ int getFramerate() { return this->fps; };
+ GUID getChroma() { return this->chroma; };
+
+ int getMatchScore(int w, int h);
+ bool isRGB();
+
+private:
+ int width;
+ int height;
+ int fps;
+ GUID chroma;
+};
+
+
+#endif
diff --git a/plugins/pluginDirectShow/internals/DSCaptureGraph.cxx b/plugins/pluginDirectShow/internals/DSCaptureGraph.cxx
new file mode 100644
index 0000000..3da6da1
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/DSCaptureGraph.cxx
@@ -0,0 +1,436 @@
+/* Copyright (C) 2011-2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#include "internals/DSCaptureGraph.h"
+#include "internals/DSUtils.h"
+#include "internals/DSCaptureUtils.h"
+
+#include "tsk_debug.h"
+
+#include <iostream>
+
+using namespace std;
+
+#ifdef _WIN32_WCE
+DSCaptureGraph::DSCaptureGraph(DSISampleGrabberCB* callback, HRESULT *hr)
+: DSBaseCaptureGraph(callback, hr)
+#else
+DSCaptureGraph::DSCaptureGraph(ISampleGrabberCB* callback, HRESULT *hr)
+: DSBaseCaptureGraph(callback, hr)
+#endif
+{
+ this->grabberCallback = callback;
+
+ this->captureFormat = NULL;
+ this->captureGraphBuilder = NULL;
+ this->graphBuilder = NULL;
+
+ this->sourceFilter = NULL;
+ this->sampleGrabberFilter = NULL;
+
+#ifdef _WIN32_WCE
+ this->colorConvertor565 = NULL;
+#else
+ this->frameRateFilter = NULL;
+#endif
+
+ this->nullRendererFilter = NULL;
+ this->grabberController = NULL;
+ this->mediaController = NULL;
+ this->mediaEventController = NULL;
+
+ this->streamConfiguration = NULL;
+
+ this->running = FALSE;
+ this->paused = FALSE;
+ this->deviceId = "";
+
+ *hr = this->createCaptureGraph();
+}
+
+DSCaptureGraph::~DSCaptureGraph()
+{
+ SAFE_RELEASE(this->streamConfiguration);
+
+ SAFE_RELEASE(this->mediaEventController);
+ SAFE_RELEASE(this->mediaController);
+ SAFE_RELEASE(this->grabberController);
+
+#if defined(_WIN32_WCE)
+ SAFE_RELEASE(this->colorConvertor565);
+#else
+#endif
+
+ SAFE_RELEASE(this->nullRendererFilter);
+ SAFE_RELEASE(this->sampleGrabberFilter);
+ SAFE_RELEASE(this->sourceFilter);
+
+ SAFE_RELEASE(this->graphBuilder);
+ SAFE_RELEASE(this->captureGraphBuilder);
+}
+
+HRESULT DSCaptureGraph::setSource(const std::string &devicePath)
+{
+ HRESULT hr = E_FAIL;
+
+ if (this->sourceFilter){
+ this->graphBuilder->RemoveFilter(this->sourceFilter);
+ }
+
+ SAFE_RELEASE(this->streamConfiguration);
+ SAFE_RELEASE(this->sourceFilter);
+
+ // Create the filter
+ this->deviceId = devicePath;
+ hr = createSourceFilter(&this->deviceId, &this->sourceFilter);
+
+ if (this->sourceFilter){
+ // Gets the supported formats
+ this->supportedFormats.clear();
+ getSupportedFormats(this->sourceFilter, &this->supportedFormats);
+
+ // Query for video stream config
+ hr = this->captureGraphBuilder->FindInterface(
+ &PIN_CATEGORY_CAPTURE,
+ &MEDIATYPE_Video,
+ this->sourceFilter,
+ IID_IAMStreamConfig,
+ reinterpret_cast<void**>(&this->streamConfiguration));
+
+ hr = this->graphBuilder->AddFilter(this->sourceFilter, FILTER_WEBCAM);
+ }
+
+ return hr;
+}
+
+HRESULT DSCaptureGraph::setParameters(DSCaptureFormat *format, int framerate)
+{
+ HRESULT hr = E_FAIL;
+ AM_MEDIA_TYPE *mediaType = NULL;
+
+ if (!this->streamConfiguration) goto bail;
+
+ hr = this->streamConfiguration->GetFormat(&mediaType);
+ if (FAILED(hr)) goto bail;
+
+ VIDEOINFOHEADER* vih = reinterpret_cast<VIDEOINFOHEADER*>(mediaType->pbFormat);
+ BITMAPINFOHEADER* bih = &vih->bmiHeader;
+
+ int w = format->getWidth();
+ int h = format->getHeight();
+
+ bool wN = (bih->biWidth<0);
+ bool hN = (bih->biHeight<0);
+
+ // DIBS are DWORD aligned
+ int data_size = h * ((w * bih->biBitCount + 31) / 32) * 4;
+
+ bih->biSize = sizeof(BITMAPINFOHEADER);
+ bih->biWidth = w*(wN?-1:1);
+ bih->biHeight = h*(hN?-1:1);
+ bih->biSizeImage = data_size;
+
+ //vih->dwBitRate = framerate * data_size;
+ //vih->AvgTimePerFrame = SECONDS_TO_100NS(framerate);
+
+ mediaType->cbFormat = sizeof(VIDEOINFOHEADER);
+ //mediaType->lSampleSize = data_size;
+ mediaType->subtype = format->getChroma();
+
+ hr = this->streamConfiguration->SetFormat(mediaType);
+ if (FAILED(hr)) goto bail;
+
+#if defined(_WIN32_WCE)
+ hr = this->grabberController->SetFps((int) DS_SECONDS_FROM_100NS(vih->AvgTimePerFrame)/*format->getFramerate()*/, framerate);
+ if (FAILED(hr)) goto bail;
+ hr = this->grabberController->SetSize(w,h);
+#else
+ // Set fps using tdshow filter
+ hr = this->frameRateFilter->SetFps((int) ((float)vih->AvgTimePerFrame/10000.f)/*format->getFramerate()*/, framerate);
+#endif
+ if (FAILED(hr)) goto bail;
+
+ this->captureFormat = format;
+
+bail:
+ DeleteMediaType(mediaType);
+
+ return hr;
+}
+
+#if defined(_WIN32_WCE)
+# include "internals/wince/DSNullFilter.h"
+#endif
+
+HRESULT DSCaptureGraph::connect()
+{
+ HRESULT hr;
+
+ if (!this->sourceFilter){
+ TSK_DEBUG_ERROR("Invalid source filter");
+ return E_FAIL;
+ }
+
+ if (!this->captureFormat){
+ TSK_DEBUG_ERROR("Invalid capture format");
+ return E_FAIL;
+ }
+
+ if (!this->graphBuilder){
+ TSK_DEBUG_ERROR("Invalid grash builder");
+ return E_FAIL;
+ }
+
+ if (this->captureFormat->isRGB())
+ {
+#if defined(_WIN32_WCE)
+ hr = ConnectFilters(this->graphBuilder, this->sourceFilter, this->colorConvertor565) ; if(FAILED(hr)) { TSK_DEBUG_ERROR("ConnectFilters failed"); return hr; }
+ hr = ConnectFilters(this->graphBuilder, this->colorConvertor565, this->sampleGrabberFilter) ; if(FAILED(hr)) { TSK_DEBUG_ERROR("ConnectFilters failed"); return hr; }
+ hr = ConnectFilters(this->graphBuilder, this->sampleGrabberFilter, this->nullRendererFilter); if(FAILED(hr)) { TSK_DEBUG_ERROR("ConnectFilters failed"); return hr; }
+#else
+ hr = ConnectFilters(this->graphBuilder, this->sourceFilter, this->frameRateFilter); if(FAILED(hr)) { TSK_DEBUG_ERROR("ConnectFilters failed"); return hr; }
+ hr = ConnectFilters(this->graphBuilder, this->frameRateFilter, this->sampleGrabberFilter); if(FAILED(hr)) { TSK_DEBUG_ERROR("ConnectFilters failed"); return hr; }
+ hr = ConnectFilters(this->graphBuilder, this->sampleGrabberFilter, this->nullRendererFilter); if(FAILED(hr)) { TSK_DEBUG_ERROR("ConnectFilters failed"); return hr; }
+#endif
+ }
+ else
+ {
+#if defined(_WIN32_WCE)
+ hr = ConnectFilters(this->graphBuilder, this->sourceFilter, this->colorConvertor565) ; if(FAILED(hr))return hr;
+ hr = ConnectFilters(this->graphBuilder, this->colorConvertor565, this->sampleGrabberFilter) ; if(FAILED(hr))return hr;
+ hr = ConnectFilters(this->graphBuilder, this->sampleGrabberFilter, this->nullRendererFilter); if(FAILED(hr))return hr;
+#else
+ // No convertor needed
+ // AVI Decompressor Filter is automatically by the Filter Graph Manager when needed
+ hr = ConnectFilters(this->graphBuilder, this->sourceFilter, this->frameRateFilter); if(FAILED(hr)) { TSK_DEBUG_ERROR("ConnectFilters failed"); return hr; }
+ hr = ConnectFilters(this->graphBuilder, this->frameRateFilter, this->sampleGrabberFilter); if(FAILED(hr)) { TSK_DEBUG_ERROR("ConnectFilters failed"); return hr; }
+ hr = ConnectFilters(this->graphBuilder, this->sampleGrabberFilter, this->nullRendererFilter); if(FAILED(hr)) { TSK_DEBUG_ERROR("ConnectFilters failed"); return hr; }
+#endif
+ }
+
+ return hr;
+}
+
+HRESULT DSCaptureGraph::disconnect()
+{
+ HRESULT hr;
+
+ if (!this->sourceFilter) {
+ return E_FAIL;
+ }
+
+ if (!this->captureFormat) {
+ return E_FAIL;
+ }
+
+ if (this->captureFormat->isRGB())
+ {
+#if defined(_WIN32_WCE)
+ hr = DisconnectFilters(this->graphBuilder, this->sourceFilter, this->colorConvertor565);
+ hr = DisconnectFilters(this->graphBuilder, this->colorConvertor565, this->sampleGrabberFilter);
+ hr = DisconnectFilters(this->graphBuilder, this->sampleGrabberFilter, this->nullRendererFilter);
+#else
+ hr = DisconnectFilters(this->graphBuilder, this->sourceFilter, this->frameRateFilter);
+ hr = DisconnectFilters(this->graphBuilder, this->frameRateFilter, this->sampleGrabberFilter);
+ hr = DisconnectFilters(this->graphBuilder, this->sampleGrabberFilter, this->nullRendererFilter);
+#endif
+ }
+ else
+ {
+#if defined(_WIN32_WCE)
+ hr = DisconnectFilters(this->graphBuilder, this->sourceFilter, this->colorConvertor565); if(FAILED(hr))return hr;
+ hr = DisconnectFilters(this->graphBuilder, this->colorConvertor565, this->sampleGrabberFilter); if(FAILED(hr))return hr;
+ hr = DisconnectFilters(this->graphBuilder, this->sampleGrabberFilter, this->nullRendererFilter); if(FAILED(hr))return hr;
+#else
+ hr = DisconnectFilters(this->graphBuilder, this->sourceFilter, this->frameRateFilter);
+ hr = DisconnectFilters(this->graphBuilder, this->frameRateFilter, this->sampleGrabberFilter);
+ hr = DisconnectFilters(this->graphBuilder, this->sampleGrabberFilter, this->nullRendererFilter);
+#endif
+ }
+
+ return hr;
+}
+
+HRESULT DSCaptureGraph::start()
+{
+ HRESULT hr;
+
+ if (isRunning() && !isPaused()) {
+ return S_OK;
+ }
+
+ //this->mediaController->Stop();
+
+ hr = this->mediaController ? this->mediaController->Run() : E_POINTER;
+ /*if (hr == S_FALSE)
+ {
+ cerr << "DSCaptureGraph::mediaController->Start() has failed with " << hr << ". Waiting for transition." << endl;
+ FILTER_STATE pfs;
+ hr = this->mediaController->GetState(2500, (OAFilterState*) &pfs);
+ hr = this->mediaController->Run();
+ }*/
+
+ if (!SUCCEEDED(hr))
+ {
+#if defined(_WIN32_WCE)
+ MessageBox(NULL, _T("Starting DirectShow Graph Failed"), _T("Failure"), MB_OK);
+ //assert(1==15);
+#endif
+ TSK_DEBUG_ERROR("DSCaptureGraph::mediaController->Run() has failed with %ld", hr);
+ return hr;
+ }
+ this->running = true;
+ return hr;
+}
+
+HRESULT DSCaptureGraph::pause()
+{
+ HRESULT hr = S_OK;
+ if (isRunning()) {
+ hr = this->mediaController->Pause();
+ if (SUCCEEDED(hr)) {
+ this->paused = TRUE;
+ }
+ }
+ return hr;
+}
+
+HRESULT DSCaptureGraph::stop()
+{
+ HRESULT hr;
+#if 0 // Must not
+ hr = this->mediaController->Pause();
+ if (hr == S_FALSE)
+ {
+ TSK_DEBUG_ERROR("DSCaptureGraph::mediaController->Pause() has failed with %ld. Waiting for transition.", hr);
+ FILTER_STATE pfs;
+ hr = this->mediaController->GetState(2500, (OAFilterState*) &pfs);
+ }
+#endif
+ hr = this->mediaController->Stop();
+ if (!SUCCEEDED(hr))
+ {
+ TSK_DEBUG_ERROR("DSCaptureGraph::mediaController->Stop() has failed with %ld", hr);
+ }
+ this->running = false;
+ this->paused = false;
+ return hr;
+}
+
+bool DSCaptureGraph::isRunning()
+{
+ return this->running;
+}
+
+bool DSCaptureGraph::isPaused()
+{
+ return this->paused;
+}
+
+HRESULT DSCaptureGraph::getConnectedMediaType(AM_MEDIA_TYPE *mediaType)
+{
+#if defined(_WIN32_WCE)
+ memmove(mediaType, &this->grabberController->GetMediaType(), sizeof(AM_MEDIA_TYPE));
+ return S_OK;
+#else
+ return this->grabberController->GetConnectedMediaType(mediaType);
+#endif
+}
+
+HRESULT DSCaptureGraph::createCaptureGraph()
+{
+ HRESULT hr;
+
+#if defined(_WIN32_WCE)
+ // Create capture graph builder
+ CHECK_HR(hr = COCREATE(CLSID_CaptureGraphBuilder, IID_ICaptureGraphBuilder2, this->captureGraphBuilder));
+ CHECK_HR(hr = COCREATE(CLSID_FilterGraph, IID_IGraphBuilder, this->graphBuilder));
+ CHECK_HR(hr = this->captureGraphBuilder->SetFiltergraph(this->graphBuilder));
+
+ // Create filters
+ LPUNKNOWN pUnk1 = NULL, pUnk2 = NULL;
+ CHECK_HR(hr = COCREATE(CLSID_Colour, IID_IBaseFilter, this->colorConvertor565));
+ this->sampleGrabberFilter = new DSSampleGrabber(FITLER_SAMPLE_GRABBER, pUnk1, &hr); CHECK_HR(hr);
+ this->nullRendererFilter = new DSNullFilter(/*FILTER_NULL_RENDERER,*/ pUnk2, &hr); CHECK_HR(hr);
+ this->grabberController = (DSSampleGrabber*)(this->sampleGrabberFilter); if (!this->grabberController) CHECK_HR(E_FAIL);
+
+ // Add Filters
+ CHECK_HR(hr = this->graphBuilder->AddFilter(this->colorConvertor565, FILTER_COLOR_CONVERTOR_565));
+ CHECK_HR(hr = this->graphBuilder->AddFilter(this->sampleGrabberFilter, FITLER_SAMPLE_GRABBER));
+ CHECK_HR(hr = this->graphBuilder->AddFilter(this->nullRendererFilter, FILTER_NULL_RENDERER));
+
+ // Find media control
+ CHECK_HR(hr = QUERY(this->graphBuilder, IID_IMediaControl, this->mediaController));
+
+ // Set callback
+ CHECK_HR(hr = this->grabberController->SetCallback(this->grabberCallback));
+#else
+ // Create capture graph builder
+ CHECK_HR(hr = COCREATE(CLSID_CaptureGraphBuilder2, IID_ICaptureGraphBuilder2, this->captureGraphBuilder));
+
+ // Create the graph builder
+ CHECK_HR(hr = COCREATE(CLSID_FilterGraph, IID_IGraphBuilder, this->graphBuilder));
+
+ // Initialize the Capture Graph Builder.
+ CHECK_HR(hr = this->captureGraphBuilder->SetFiltergraph(this->graphBuilder));
+
+ // Create the sample grabber filter
+ CHECK_HR(hr = COCREATE(CLSID_SampleGrabber, IID_IBaseFilter, this->sampleGrabberFilter));
+
+ // Create tdshow filter
+ LPUNKNOWN pUnk = NULL;
+ this->frameRateFilter = new DSFrameRateFilter(FILTER_FRAMERATE, pUnk, &hr); CHECK_HR(hr);
+ if (!this->frameRateFilter == NULL) CHECK_HR(E_FAIL);
+
+ // Create the NULL renderer
+ CHECK_HR(hr = COCREATE(CLSID_NullRenderer, IID_IBaseFilter, this->nullRendererFilter));
+
+ // Add sample grabber to the graph
+ CHECK_HR(hr = this->graphBuilder->AddFilter(this->sampleGrabberFilter, FITLER_SAMPLE_GRABBER));
+
+ // Add null renderer to the graph
+ CHECK_HR(hr = this->graphBuilder->AddFilter(this->nullRendererFilter, FILTER_NULL_RENDERER));
+
+ // Add tdshow filter
+ CHECK_HR(hr = this->graphBuilder->AddFilter(this->frameRateFilter, FILTER_FRAMERATE));
+
+ // Find media control
+ CHECK_HR(hr = QUERY(this->graphBuilder, IID_IMediaControl, this->mediaController));
+
+ // Create the sample grabber
+ CHECK_HR(hr = QUERY(this->sampleGrabberFilter, IID_ISampleGrabber, this->grabberController));
+
+ // Set the sample grabber media type (RGB24)
+ // TODO : CHECK
+ AM_MEDIA_TYPE mt;
+ ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
+ mt.majortype = MEDIATYPE_Video;
+ mt.subtype = MEDIASUBTYPE_RGB24;
+ mt.formattype = FORMAT_VideoInfo;
+
+ CHECK_HR(hr = this->grabberController->SetMediaType(&mt));
+
+ // Set sample grabber media type
+ this->grabberController->SetOneShot(FALSE);
+ this->grabberController->SetBufferSamples(FALSE);
+
+ CHECK_HR(hr = this->grabberController->SetCallback(this->grabberCallback, 1));
+#endif
+
+bail:
+ return hr;
+} \ No newline at end of file
diff --git a/plugins/pluginDirectShow/internals/DSCaptureGraph.h b/plugins/pluginDirectShow/internals/DSCaptureGraph.h
new file mode 100644
index 0000000..6bf8862
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/DSCaptureGraph.h
@@ -0,0 +1,106 @@
+/* Copyright (C) 2011-2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#ifndef PLUGIN_DSHOW_DSCAPTUREGRAPH_H
+#define PLUGIN_DSHOW_DSCAPTUREGRAPH_H
+
+#include "plugin_dshow_config.h"
+#include <vector>
+#include <control.h>
+#include "internals/DSBaseCaptureGraph.h"
+#include "internals/DSFrameRateFilter.h"
+
+#if defined(_WIN32_WCE)
+# include "internals/wince/DSSampleGrabber.h"
+# include "internals/wince/DSNullFilter.h"
+# include "internals/wince/DSISampleGrabberCB.h"
+#else
+# include <qedit.h>
+#endif
+
+
+class DSCaptureGraph : public DSBaseCaptureGraph
+{
+public:
+#ifdef _WIN32_WCE
+ DSCaptureGraph(DSISampleGrabberCB* callback, HRESULT *hr);
+#else
+ DSCaptureGraph(ISampleGrabberCB* callback, HRESULT *hr);
+#endif
+ virtual ~DSCaptureGraph();
+
+ std::vector<DSCaptureFormat> *getFormats() { return &this->supportedFormats; };
+
+ HRESULT setSource(const std::string &devicePath);
+ HRESULT setParameters(DSCaptureFormat *format, int framerate);
+
+ HRESULT connect();
+ HRESULT disconnect();
+
+ HRESULT start();
+ HRESULT stop();
+ HRESULT pause();
+ bool isRunning();
+ bool isPaused();
+
+ std::string getDeviceId() const { return this->deviceId; };
+
+ HRESULT getConnectedMediaType(AM_MEDIA_TYPE *mediaType);
+
+private:
+ HRESULT createCaptureGraph();
+
+private:
+#ifdef _WIN32_WCE
+ DSISampleGrabberCB *grabberCallback;
+#else
+ ISampleGrabberCB *grabberCallback;
+#endif
+
+ ICaptureGraphBuilder2 *captureGraphBuilder;
+ IGraphBuilder *graphBuilder;
+
+ IBaseFilter *sourceFilter;
+ IBaseFilter *nullRendererFilter;
+ IBaseFilter *sampleGrabberFilter;
+
+#ifdef _WIN32_WCE
+ IBaseFilter *colorConvertor565; //http://msdn.microsoft.com/en-us/library/aa926076.aspx
+#else
+ DSFrameRateFilter *frameRateFilter;
+#endif
+
+#ifdef _WIN32_WCE
+ DSSampleGrabber *grabberController;
+#else
+ ISampleGrabber *grabberController;
+#endif
+
+ IMediaControl *mediaController;
+ IMediaEventEx *mediaEventController;
+
+ IAMStreamConfig *streamConfiguration;
+
+ std::vector<DSCaptureFormat> supportedFormats;
+ DSCaptureFormat *captureFormat;
+
+ bool running;
+ bool paused;
+ std::string deviceId;
+};
+
+#endif
diff --git a/plugins/pluginDirectShow/internals/DSCaptureUtils.cxx b/plugins/pluginDirectShow/internals/DSCaptureUtils.cxx
new file mode 100644
index 0000000..d95f996
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/DSCaptureUtils.cxx
@@ -0,0 +1,377 @@
+/* Copyright (C) 2011-2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#include "internals/DSUtils.h"
+#include "internals/DSCaptureUtils.h"
+#include <amvideo.h>
+#include <uuids.h>
+#include <mtype.h>
+
+#if defined (_WIN32_WCE)
+#include <atlbase.h>
+#include <atlstr.h>
+#else
+#include <atlconv.h>
+#endif
+#include <iostream>
+#include <assert.h>
+
+#include "tsk_debug.h"
+
+#if defined (_WIN32_WCE)
+# include "internals/wince/cpropertybag.h"
+#endif
+
+HRESULT enumerateCaptureDevices(const std::string &prefix, std::vector<VideoGrabberName> *names)
+{
+ HRESULT hr = S_OK;
+
+#ifdef _WIN32_WCE
+
+ // FIXME: use FindNextDevice to query all devices
+ HANDLE handle = NULL;
+ DEVMGR_DEVICE_INFORMATION di;
+
+ TCHAR pwzName[MAX_PATH]; memset(pwzName,NULL,MAX_PATH);
+
+ GUID guidCamera = { 0xCB998A05, 0x122C, 0x4166, 0x84, 0x6A,
+ 0x93, 0x3E, 0x4D, 0x7E, 0x3C, 0x86 }; // http://msdn.microsoft.com/en-us/library/aa918757.aspx
+
+ di.dwSize = sizeof(di);
+
+ for( int i=0; ; i++)
+ {
+ if(0 == i)
+ { /* 1st time */
+ handle = FindFirstDevice( DeviceSearchByGuid, &guidCamera, &di );
+ if(!handle || !di.hDevice)
+ {
+ hr = ( HRESULT_FROM_WIN32( GetLastError() ));
+ goto bail;
+ }
+ }
+ else if(handle)
+ { /* 2nd or 3rd time */
+ BOOL ret = FindNextDevice(handle, &di);
+ if(!ret || !di.hDevice)
+ {
+ /* No 2nd or 3rd camera ==> do not return error*/
+ goto bail;
+ }
+ }
+ else assert(0);
+
+ StringCchCopy( pwzName, MAX_PATH, di.szDeviceName );
+
+ /* from LPWSTR to LPSTR */
+ char mbstr_name[MAX_PATH]; memset(mbstr_name,NULL,MAX_PATH);
+ wcstombs(mbstr_name, pwzName, MAX_PATH);
+
+ VideoGrabberName grabberName(std::string((const char*)mbstr_name), std::string((const char*)mbstr_name));
+ names->push_back(grabberName);
+ }
+
+bail:
+ /* close */
+ if(handle) FindClose( handle );
+
+#else
+ ICreateDevEnum *deviceEnum;
+ IEnumMoniker *enumerator;
+ IMoniker *moniker;
+
+ // Create the System Device Enumerator
+ hr = COCREATE(CLSID_SystemDeviceEnum, IID_ICreateDevEnum, deviceEnum);
+ if (FAILED(hr)) goto bail;
+
+ // Ask for a device enumerator
+ hr = deviceEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &enumerator, INCLUDE_CATEGORY_FLAG);
+ if (FAILED(hr)) goto bail;
+
+ // hr = S_FALSE and enumerator is NULL if there is no device to enumerate
+ if (!enumerator) goto bail;
+
+ USES_CONVERSION;
+
+ while (enumerator->Next(1, &moniker, NULL) == S_OK)
+ {
+ // Get the properties bag for each device
+ IPropertyBag *propBag;
+ hr = moniker->BindToStorage(0, 0, IID_IPropertyBag, reinterpret_cast<void**>(&propBag));
+ if (FAILED(hr))
+ {
+ SAFE_RELEASE(moniker);
+ continue;
+ }
+
+ std::string name;
+ std::string description;
+
+ VARIANT varName;
+ VariantInit(&varName);
+ VARIANT varDescription;
+ VariantInit(&varDescription);
+
+ // Find the device path (uniqueness is guaranteed)
+ hr = propBag->Read(L"DevicePath", &varName, 0);
+ if (SUCCEEDED(hr))
+ {
+ if (prefix != "") name = prefix + ":";
+ name = name + std::string(W2A(varName.bstrVal));
+ }
+
+ // Find friendly name or the description
+ hr = propBag->Read(L"FriendlyName", &varDescription, 0);
+ if (SUCCEEDED(hr))
+ {
+ description = std::string(W2A(varDescription.bstrVal));
+ }
+ else
+ {
+ hr = propBag->Read(L"Description", &varDescription, 0);
+ if (SUCCEEDED(hr)) description = std::string(W2A(varDescription.bstrVal));
+ }
+
+ hr = VariantClear(&varName);
+ hr = VariantClear(&varDescription);
+
+ SAFE_RELEASE(propBag);
+ SAFE_RELEASE(moniker);
+
+ // Add it to the list
+ if (name != "")
+ {
+ VideoGrabberName grabberName(name, description);
+ names->push_back(grabberName);
+ }
+ }
+
+bail:
+ SAFE_RELEASE(enumerator);
+ SAFE_RELEASE(deviceEnum);
+#endif
+
+ return hr;
+}
+
+HRESULT createSourceFilter(std::string *devicePath, IBaseFilter **sourceFilter)
+{
+ HRESULT hr;
+
+ IEnumMoniker *enumerator = NULL;
+ IMoniker *moniker = NULL;
+ bool found = false;
+
+ // Set sourceFilter to null
+ SAFE_RELEASE((*sourceFilter));
+
+#if defined( _WIN32_WCE)
+ CPropertyBag pBag;
+ HANDLE handle = NULL;
+ DEVMGR_DEVICE_INFORMATION di;
+ TCHAR pwzName[MAX_PATH];
+ CComVariant varCamName;
+ IPersistPropertyBag *propBag = NULL;
+ GUID guidCamera = { 0xCB998A05, 0x122C, 0x4166, 0x84, 0x6A,
+ 0x93, 0x3E, 0x4D, 0x7E, 0x3C, 0x86 }; // http://msdn.microsoft.com/en-us/library/aa918757.aspx
+
+ di.dwSize = sizeof(di);
+
+ for( int i=0; ; i++)
+ {
+ if(0 == i)
+ { /* 1st time */
+ handle = FindFirstDevice( DeviceSearchByGuid, &guidCamera, &di );
+ if(!handle || !di.hDevice)
+ {
+ hr = ( HRESULT_FROM_WIN32( GetLastError() ));
+ goto bail;
+ }
+ }
+ else if(handle)
+ { /* 2nd or 3rd time */
+ BOOL ret = FindNextDevice(handle, &di);
+ if(!ret || !di.hDevice)
+ {
+ /* No 2nd or 3rd camera ==> do not return error*/
+ goto bail;
+ }
+ }
+ else assert(0);
+
+ StringCchCopy( pwzName, MAX_PATH, di.szDeviceName );
+
+ /* from LPWSTR to LPSTR */
+ char mbstr_name[MAX_PATH];
+ memset(mbstr_name,NULL,MAX_PATH);
+ wcstombs(mbstr_name, pwzName, MAX_PATH);
+
+ if((std::string((const char*)mbstr_name) == (*devicePath)) || ("0" == (*devicePath)))
+ {
+ varCamName = pwzName;
+ if( varCamName.vt != VT_BSTR )
+ {
+ hr = E_OUTOFMEMORY;
+ goto bail;
+ }
+
+ // Create Source filter
+ hr = COCREATE(CLSID_VideoCapture, IID_IBaseFilter, *sourceFilter);
+ if(FAILED(hr)) goto bail;
+
+ // Query PropertyBag
+ hr = QUERY((*sourceFilter), IID_IPersistPropertyBag, propBag);
+ if(FAILED(hr)) goto bail;
+
+ hr = pBag.Write( L"VCapName", &varCamName );
+ if(FAILED(hr)) goto bail;
+
+ hr = propBag->Load( &pBag, NULL );
+ if(FAILED(hr)) goto bail;
+ }
+ }
+#else
+ ICreateDevEnum *deviceEnum = NULL;
+ IPropertyBag *propBag = NULL;
+
+ // Create the System Device Enumerator
+ hr = COCREATE(CLSID_SystemDeviceEnum, IID_ICreateDevEnum, deviceEnum);
+ if (FAILED(hr)){
+ goto bail;
+ }
+
+ // Ask for a device enumerator
+ hr = deviceEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &enumerator, INCLUDE_CATEGORY_FLAG);
+ if(FAILED(hr)){
+ goto bail;
+ }
+
+ // hr = S_FALSE and enumerator is NULL if there is no device to enumerate
+ if(!enumerator){
+ goto bail;
+ }
+
+ USES_CONVERSION;
+
+ while (!found && (enumerator->Next(1, &moniker, NULL) == S_OK)){
+ // Get the properties bag for each device
+ hr = moniker->BindToStorage(0, 0, IID_IPropertyBag, reinterpret_cast<void**>(&propBag));
+ if (FAILED(hr)){
+ SAFE_RELEASE(moniker);
+ continue;
+ }
+
+ std::string name;
+
+ VARIANT varName;
+ VariantInit(&varName);
+
+ // Find the device path (uniqueness is guaranteed)
+ hr = propBag->Read(L"DevicePath", &varName, 0);
+ if (SUCCEEDED(hr)) name = std::string(W2A(varName.bstrVal));
+
+ // Check for device path
+ // "Null" means first found
+ if ((name == (*devicePath)) ||
+ ("Null" == (*devicePath)))
+ {
+ hr = moniker->BindToObject(0, 0, IID_IBaseFilter, reinterpret_cast<void**>(&(*sourceFilter)));
+ if (SUCCEEDED(hr)){
+ (*devicePath) = name;
+ found = true;
+ }
+ }
+
+ hr = VariantClear(&varName);
+
+ SAFE_RELEASE(propBag);
+ SAFE_RELEASE(moniker);
+ }
+#endif
+
+bail:
+#ifdef _WIN32_WCE
+ if(handle) FindClose(handle);
+#else
+ SAFE_RELEASE(deviceEnum);
+#endif
+ SAFE_RELEASE(moniker);
+ SAFE_RELEASE(enumerator);
+ SAFE_RELEASE(propBag);
+
+ return hr;
+}
+
+HRESULT getSupportedFormats(IBaseFilter *sourceFilter, std::vector<DSCaptureFormat> *formats)
+{
+ HRESULT hr = E_FAIL;
+ IPin *pinOut = NULL;
+ IAMStreamConfig *streamConfig = NULL;
+ AM_MEDIA_TYPE *mediaType = NULL;
+ int count, size;
+
+ // Check source filter pointer
+ if (!sourceFilter) goto bail;
+
+ pinOut = GetPin(sourceFilter, PINDIR_OUTPUT);
+ if(!pinOut) goto bail;
+
+ // Retrieve the stream config interface
+ hr = QUERY(pinOut, IID_IAMStreamConfig, streamConfig);
+ if (FAILED(hr)) goto bail;
+
+ // Get the number of capabilities
+ hr = streamConfig->GetNumberOfCapabilities(&count, &size);
+ if (FAILED(hr)) goto bail;
+
+ hr = streamConfig->GetFormat(&mediaType);
+ if (FAILED(hr)) goto bail;
+
+ // Iterate through the formats
+ for (int i = 0; i < count; i++){
+ VIDEO_STREAM_CONFIG_CAPS streamConfigCaps;
+
+ hr = streamConfig->GetStreamCaps(i, &mediaType, reinterpret_cast<BYTE*>(&streamConfigCaps));
+
+ if (FAILED(hr)){
+ TSK_DEBUG_ERROR("Failed to get Stream caps");
+ break;
+ }
+
+ if (streamConfigCaps.guid == FORMAT_VideoInfo){
+ VIDEOINFOHEADER* vih = reinterpret_cast<VIDEOINFOHEADER*>(mediaType->pbFormat);
+ BITMAPINFOHEADER* bih = &vih->bmiHeader;
+
+ int width = abs(bih->biWidth);
+ int height = abs(bih->biHeight);
+ int fps = (int) ((float)(vih->AvgTimePerFrame)/10000.f);
+ GUID chroma = mediaType->subtype;
+
+ // Add format to the list
+ DSCaptureFormat format(width, height, fps, chroma);
+ formats->push_back(format);
+ }
+
+ DeleteMediaType(mediaType);
+ }
+
+bail:
+ SAFE_RELEASE(streamConfig);
+ SAFE_RELEASE(pinOut);
+
+ return hr;
+}
diff --git a/plugins/pluginDirectShow/internals/DSCaptureUtils.h b/plugins/pluginDirectShow/internals/DSCaptureUtils.h
new file mode 100644
index 0000000..7d99ed2
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/DSCaptureUtils.h
@@ -0,0 +1,60 @@
+/* Copyright (C) 2011-2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#ifndef PLUGIN_DSHOW_DSCAPTUREUTILS_H
+#define PLUGIN_DSHOW_DSCAPTUREUTILS_H
+
+#include "plugin_dshow_config.h"
+#include "internals/DSCaptureFormat.h"
+#include "internals/VideoGrabberName.h"
+
+#include <vector>
+
+// --------------------------------------------------------------------------------
+
+#ifdef INCLUDE_VFW_DEVICES
+#define INCLUDE_CATEGORY_FLAG 0
+#else
+#define INCLUDE_CATEGORY_FLAG CDEF_DEVMON_FILTER | CDEF_DEVMON_PNP_DEVICE
+#endif
+
+// --------------------------------------------------------------------------------
+
+/**
+* \brief Fills in a vector with VideoGrabberName instances constructed from the video capture devices.
+* \param A pointer to the device vector to append
+* \return An HRESULT value
+*/
+HRESULT enumerateCaptureDevices(const std::string &prefix, std::vector<VideoGrabberName> *names);
+
+/**
+* \brief Fills in a vector with VideoGrabberName instances constructed from the video capture devices.
+* \param A constant string containing a device path
+* \param A pointer to the filter that will contains the filter created or NULL if not the device is not found
+* \return An HRESULT value
+*/
+HRESULT createSourceFilter(std::string *devicePath, IBaseFilter **sourceFilter);
+
+/**
+* \brief Fills in a vector with DSCaptureFormat instances constructed from the given video capture device.
+* \param An instance of a capture device
+* \param A pointer to the format vector to append
+* \return An HRESULT value
+*/
+HRESULT getSupportedFormats(IBaseFilter *sourceFilter, std::vector<DSCaptureFormat> *formats);
+
+#endif
diff --git a/plugins/pluginDirectShow/internals/DSDibHelper.cxx b/plugins/pluginDirectShow/internals/DSDibHelper.cxx
new file mode 100644
index 0000000..b7f40d5
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/DSDibHelper.cxx
@@ -0,0 +1,80 @@
+#if !defined(_WIN32_WCE)
+//------------------------------------------------------------------------------
+// File: DibHelper.cpp
+//
+// Desc: DirectShow sample code - In-memory push mode source filter
+// Helper routines for manipulating bitmaps.
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------------------------
+
+#include <windows.h>
+
+#include "dsdibhelper.h"
+
+
+HBITMAP CopyScreenToBitmap(LPRECT lpRect, BYTE *pData, BITMAPINFO *pHeader)
+{
+ HDC hScrDC, hMemDC; // screen DC and memory DC
+ HBITMAP hBitmap, hOldBitmap; // handles to deice-dependent bitmaps
+ int nX, nY, nX2, nY2; // coordinates of rectangle to grab
+ int nWidth, nHeight; // DIB width and height
+ int xScrn, yScrn; // screen resolution
+
+ // check for an empty rectangle
+ if (IsRectEmpty(lpRect))
+ return NULL;
+
+ // create a DC for the screen and create
+ // a memory DC compatible to screen DC
+ hScrDC = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
+ hMemDC = CreateCompatibleDC(hScrDC);
+
+ // get points of rectangle to grab
+ nX = lpRect->left;
+ nY = lpRect->top;
+ nX2 = lpRect->right;
+ nY2 = lpRect->bottom;
+
+ // get screen resolution
+ xScrn = GetDeviceCaps(hScrDC, HORZRES);
+ yScrn = GetDeviceCaps(hScrDC, VERTRES);
+
+ //make sure bitmap rectangle is visible
+ if (nX < 0)
+ nX = 0;
+ if (nY < 0)
+ nY = 0;
+ if (nX2 > xScrn)
+ nX2 = xScrn;
+ if (nY2 > yScrn)
+ nY2 = yScrn;
+
+ nWidth = nX2 - nX;
+ nHeight = nY2 - nY;
+
+ // create a bitmap compatible with the screen DC
+ hBitmap = CreateCompatibleBitmap(hScrDC, nWidth, nHeight);
+
+ // select new bitmap into memory DC
+ hOldBitmap = (HBITMAP) SelectObject(hMemDC, hBitmap);
+
+ // bitblt screen DC to memory DC
+ BitBlt(hMemDC, 0, 0, nWidth, nHeight, hScrDC, nX, nY, SRCCOPY);
+
+ // select old bitmap back into memory DC and get handle to
+ // bitmap of the screen
+ hBitmap = (HBITMAP) SelectObject(hMemDC, hOldBitmap);
+
+ // Copy the bitmap data into the provided BYTE buffer
+ GetDIBits(hScrDC, hBitmap, 0, nHeight, pData, pHeader, DIB_RGB_COLORS);
+
+ // clean up
+ DeleteDC(hScrDC);
+ DeleteDC(hMemDC);
+
+ // return handle to the bitmap
+ return hBitmap;
+}
+
+#endif /* _WIN32_WCE */
diff --git a/plugins/pluginDirectShow/internals/DSDibHelper.h b/plugins/pluginDirectShow/internals/DSDibHelper.h
new file mode 100644
index 0000000..7b5481e
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/DSDibHelper.h
@@ -0,0 +1,106 @@
+//------------------------------------------------------------------------------
+// File: DibHelper.H
+//
+// Desc: DirectShow sample code - Helper code for bitmap manipulation
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------------------------
+
+#ifndef PLUGIN_DSHOW_DSDIBHELPER_H
+#define PLUGIN_DSHOW_DSDIBHELPER_H
+
+#define HDIB HANDLE
+
+/* DIB macros */
+#define IS_WIN30_DIB(lpbi) ((*(LPDWORD)(lpbi)) == sizeof(BITMAPINFOHEADER))
+#define RECTWIDTH(lpRect) ((lpRect)->right - (lpRect)->left)
+#define RECTHEIGHT(lpRect) ((lpRect)->bottom - (lpRect)->top)
+
+// Function prototypes
+HDIB BitmapToDIB (HBITMAP hBitmap, HPALETTE hPal);
+HDIB ChangeBitmapFormat (HBITMAP hBitmap,
+ WORD wBitCount,
+ DWORD dwCompression,
+ HPALETTE hPal);
+HDIB ChangeDIBFormat (HDIB hDIB, WORD wBitCount, DWORD dwCompression);
+
+HBITMAP CopyScreenToBitmap(LPRECT lpRect, BYTE *pData, BITMAPINFO *pHeader);
+HDIB CopyScreenToDIB (LPRECT);
+HBITMAP CopyWindowToBitmap (HWND, WORD);
+HDIB CopyWindowToDIB (HWND, WORD);
+
+HPALETTE CreateDIBPalette (HDIB);
+HDIB CreateDIB(DWORD, DWORD, WORD);
+WORD DestroyDIB (HDIB);
+
+void DIBError (int ErrNo);
+DWORD DIBHeight (LPSTR lpDIB);
+WORD DIBNumColors (LPSTR lpDIB);
+HBITMAP DIBToBitmap (HDIB hDIB, HPALETTE hPal);
+DWORD DIBWidth (LPSTR lpDIB);
+
+LPSTR FindDIBBits (LPSTR lpDIB);
+HPALETTE GetSystemPalette (void);
+HDIB LoadDIB (LPSTR);
+
+BOOL PaintBitmap (HDC, LPRECT, HBITMAP, LPRECT, HPALETTE);
+BOOL PaintDIB (HDC, LPRECT, HDIB, LPRECT, HPALETTE);
+
+int PalEntriesOnDevice (HDC hDC);
+WORD PaletteSize (LPSTR lpDIB);
+WORD SaveDIB (HDIB, LPSTR);
+
+#endif /* PLUGIN_DSHOW_DSDIBHELPER_H */
+//------------------------------------------------------------------------------
+// File: DibHelper.H
+//
+// Desc: DirectShow sample code - Helper code for bitmap manipulation
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------------------------
+
+#ifndef PLUGIN_DSHOW_DSDIBHELPER_H
+#define PLUGIN_DSHOW_DSDIBHELPER_H
+
+#define HDIB HANDLE
+
+/* DIB macros */
+#define IS_WIN30_DIB(lpbi) ((*(LPDWORD)(lpbi)) == sizeof(BITMAPINFOHEADER))
+#define RECTWIDTH(lpRect) ((lpRect)->right - (lpRect)->left)
+#define RECTHEIGHT(lpRect) ((lpRect)->bottom - (lpRect)->top)
+
+// Function prototypes
+HDIB BitmapToDIB (HBITMAP hBitmap, HPALETTE hPal);
+HDIB ChangeBitmapFormat (HBITMAP hBitmap,
+ WORD wBitCount,
+ DWORD dwCompression,
+ HPALETTE hPal);
+HDIB ChangeDIBFormat (HDIB hDIB, WORD wBitCount, DWORD dwCompression);
+
+HBITMAP CopyScreenToBitmap(LPRECT lpRect, BYTE *pData, BITMAPINFO *pHeader);
+HDIB CopyScreenToDIB (LPRECT);
+HBITMAP CopyWindowToBitmap (HWND, WORD);
+HDIB CopyWindowToDIB (HWND, WORD);
+
+HPALETTE CreateDIBPalette (HDIB);
+HDIB CreateDIB(DWORD, DWORD, WORD);
+WORD DestroyDIB (HDIB);
+
+void DIBError (int ErrNo);
+DWORD DIBHeight (LPSTR lpDIB);
+WORD DIBNumColors (LPSTR lpDIB);
+HBITMAP DIBToBitmap (HDIB hDIB, HPALETTE hPal);
+DWORD DIBWidth (LPSTR lpDIB);
+
+LPSTR FindDIBBits (LPSTR lpDIB);
+HPALETTE GetSystemPalette (void);
+HDIB LoadDIB (LPSTR);
+
+BOOL PaintBitmap (HDC, LPRECT, HBITMAP, LPRECT, HPALETTE);
+BOOL PaintDIB (HDC, LPRECT, HDIB, LPRECT, HPALETTE);
+
+int PalEntriesOnDevice (HDC hDC);
+WORD PaletteSize (LPSTR lpDIB);
+WORD SaveDIB (HDIB, LPSTR);
+
+#endif /* PLUGIN_DSHOW_DSDIBHELPER_H */ \ No newline at end of file
diff --git a/plugins/pluginDirectShow/internals/DSDisplay.cxx b/plugins/pluginDirectShow/internals/DSDisplay.cxx
new file mode 100644
index 0000000..326b86c
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/DSDisplay.cxx
@@ -0,0 +1,622 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+#include "internals/DSDisplay.h"
+#include "internals/DSUtils.h"
+
+#include "tsk_list.h"
+#include "tsk_debug.h"
+
+#include <string>
+
+using namespace std;
+
+#define USE_OVERLAY 0
+#define OVERLAY_TIMEOUT 3
+#define WM_GRAPHNOTIFY WM_APP + 1
+
+#define FSCREEN_MIN_IDEAL_WIDTH 352
+#define FSCREEN_MIN_IDEAL_HEIGHT 288
+
+typedef struct tdshow_display_s
+{
+ TSK_DECLARE_OBJECT;
+
+ HWND hwnd;
+ DSDisplay* display;
+}
+tdshow_display_t;
+typedef tsk_list_t tdshow_displays_L_t;
+const tsk_object_def_t *tdshow_display_def_t;
+
+// Static list to find which display is link to a given hWnd
+static tdshow_displays_L_t* __directshow__Displays = tsk_null;
+
+/*== Predicate function to find tdshow_display_t object by HWND. */
+static int __pred_find_display_by_hwnd(const tsk_list_item_t *item, const void *hWnd)
+{
+ if(item && item->data){
+ const tdshow_display_t *display = (const tdshow_display_t *)item->data;
+ int ret = 0;
+ tsk_subsat_int32_ptr(display->hwnd, *((HWND*)hWnd), &ret);
+ return ret;
+ }
+ return -1;
+}
+
+// C Callback that dispatch event to the right display
+static LRESULT CALLBACK __directshow__WndProcWindow(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ LRESULT result = FALSE;
+ BOOL resultSet = FALSE;
+
+ if(__directshow__Displays){
+ tsk_list_lock(__directshow__Displays);
+
+ const tdshow_display_t *display = (const tdshow_display_t *)tsk_list_find_object_by_pred(__directshow__Displays, __pred_find_display_by_hwnd, &hWnd);
+ if((resultSet = (display && display->display))){
+ result = display->display->handleEvents(hWnd, uMsg, wParam, lParam);
+ }
+
+ tsk_list_unlock(__directshow__Displays);
+ }
+
+ return resultSet ? result : DefWindowProc(hWnd, uMsg, wParam, lParam);
+}
+
+
+DSDisplay::DSDisplay(HRESULT *hr)
+{
+ this->window = NULL;
+ this->parentWindowProc = NULL;
+ this->hooked = false;
+ this->fullscreen = false;
+ this->bPluginFirefox = false;
+ this->top = 0;
+ this->left = 0;
+ this->width = this->imgWidth = 176;
+ this->height = this->imgHeight = 144;
+ this->fps = 15;
+
+ this->graph = new DSDisplayGraph(hr);
+ if (FAILED(*hr)) return;
+#if USE_OVERLAY
+ this->overlay = new DSDisplayOverlay();
+#else
+ this->overlay = NULL;
+#endif
+
+ this->graph->getVideoWindow()->put_Visible(OAFALSE);
+}
+
+DSDisplay::~DSDisplay()
+{
+ this->unhook();
+
+ SAFE_DELETE_PTR(this->overlay);
+ SAFE_DELETE_PTR(this->graph);
+}
+
+void DSDisplay::start()
+{
+ if (!this->graph->isRunning()){
+ this->hook();
+ }
+ if (!this->graph->isRunning() || this->graph->isPaused()){
+ this->graph->start();
+ }
+ this->graph->getVideoWindow()->put_Visible(OATRUE);
+}
+
+void DSDisplay::pause()
+{
+ this->graph->pause();
+}
+
+void DSDisplay::stop()
+{
+ if (this->graph->isRunning()){
+ this->setFullscreen(false);
+
+ this->graph->stop();
+ this->unhook();
+ }
+}
+
+void DSDisplay::attach(INT64 parent)
+{
+ this->attach((void*)parent);
+}
+
+void DSDisplay::attach(void *parent)
+{
+ // Don't reattach if this is the same parent
+ if (this->isAttached() && parent){
+ HWND hwnd = reinterpret_cast<HWND>(parent);
+ if (hwnd != this->window){
+ this->detach();
+ }
+ }
+
+ // Gets the handle of the parent
+ this->window = reinterpret_cast<HWND>(parent);
+ // Hook to the parent WindowProc
+ this->hook();
+
+#if USE_OVERLAY
+ // Allows the overlay to initialize
+ this->overlay->attach(this->window, this->graph);
+#endif
+}
+
+void DSDisplay::detach(void *parent)
+{
+ // The detach action is only valid and if this is the same parent
+ if (parent){
+ HWND hwnd = reinterpret_cast<HWND>(parent);
+ if (hwnd == this->window){
+ this->detach();
+ }
+ }
+}
+
+void DSDisplay::detach()
+{
+ if (!this->isAttached()){
+ return;
+ }
+
+#if USE_OVERLAY
+ // Clean up overlay
+ this->overlay->detach();
+#endif
+
+ // Unhook from the parent WindowProc
+ this->unhook();
+
+ // Set the handle of the parent to NULL
+ this->window = NULL;
+}
+
+bool DSDisplay::isAttached()
+{
+ return (this->window != NULL);
+}
+
+int DSDisplay::getWidth()
+{
+ return this->width;
+}
+
+int DSDisplay::getHeight()
+{
+ return this->height;
+}
+
+void DSDisplay::setSize(int w, int h)
+{
+ //this->width = w;
+ //this->height = h;
+
+ if (!this->fullscreen){
+ this->graph->setImageFormat(w, h);
+ if(this->hooked){
+#if 0
+ #if defined(VMR9_WINDOWLESS)
+ RECT rc;
+ SetRect(&rc, 0, 0, w, h);
+ this->graph->getWindowlessControl()->SetVideoPosition(&rc, &rc);
+ #else
+ this->graph->getVideoWindow()->SetWindowPosition(0, 0, this->width , this->height);
+ #endif
+#endif
+ }
+ }
+}
+
+void DSDisplay::applyRatio(RECT rect)
+{
+ long w = rect.right - rect.left;
+ long h = rect.bottom - rect.top;
+ float ratio = ((float)this->imgWidth/(float)this->imgHeight);
+ // (w/h)=ratio =>
+ // 1) h=w/ratio
+ // and
+ // 2) w=h*ratio
+ this->width = (int)(w/ratio) > h ? (int)(h * ratio) : w;
+ this->height = (int)(this->width/ratio) > h ? h : (int)(this->width/ratio);
+ this->left = ((w - this->width) >> 1);
+ this->top = ((h - this->height) >> 1);
+}
+
+bool DSDisplay::isFullscreen()
+{
+#if defined(VMR9_WINDOWLESS)
+ // TODO
+#else
+ long result;
+ HRESULT hr = this->graph->getVideoWindow()->get_FullScreenMode(&result);
+ if (SUCCEEDED(hr)){
+ this->fullscreen = (result == OATRUE);
+ }
+ else{
+ TSK_DEBUG_ERROR("get_FullScreenMode failed with %ld", hr);
+ this->fullscreen = FALSE;
+ }
+#endif
+ return this->fullscreen;
+}
+
+void DSDisplay::setFullscreen(bool value)
+{
+ if(!this->canFullscreen()){
+ TSK_DEBUG_WARN("Cannot fullscreen");
+ return;
+ }
+
+ HRESULT hr;
+
+#if defined(VMR9_WINDOWLESS)
+ // TODO
+#else
+ if (this->isFullscreen() == value){
+ return;
+ }
+
+ hr = this->graph->getVideoWindow()->put_FullScreenMode(value ? OATRUE : OAFALSE);
+ if (SUCCEEDED(hr)){
+ this->fullscreen = value;
+#if USE_OVERLAY
+ this->overlay->show(this->fullscreen ? (OVERLAY_TIMEOUT * this->graph->getDisplayFps()) : 0);
+#endif
+ }
+ else{
+ TSK_DEBUG_ERROR("put_FullScreenMode failed with %ld", hr);
+ }
+#endif
+}
+
+void DSDisplay::setPluginFirefox(bool value)
+{
+ bPluginFirefox = value;
+}
+
+bool DSDisplay::canFullscreen()
+{
+#if defined(VMR9_WINDOWLESS)
+ // TODO
+#else
+ if(this->graph){
+ UINT image_w, image_h;
+
+ if( this->graph->getImageFormat(image_w, image_h) ){
+ //this->graph->getVideoWindow()->GetMinIdealImageSize(&ideal_w, &ideal_h);
+ return (((long)image_w >= FSCREEN_MIN_IDEAL_WIDTH) && ((long)image_h >= FSCREEN_MIN_IDEAL_HEIGHT));
+ }
+ }
+#endif
+ return false;
+}
+
+void DSDisplay::setFps(int fps_)
+{
+ this->fps = fps_;
+ this->graph->setDisplayFps(fps_);
+}
+
+
+// w and h are the size of the buffer not the display
+void DSDisplay::handleVideoFrame(const void* data, int w, int h)
+{
+ if (this->graph->isRunning()){
+ // The graph will take care of changing the source filter if needed
+ // in case of dimension change or anything else...
+ this->graph->handleFrame(data, w, h);
+ if(this->imgWidth != w || this->imgHeight != h){
+ this->imgWidth = w;
+ this->imgHeight = h;
+ if(this->window){
+ SendMessage(this->window, WM_SIZE, SIZE_RESTORED, MAKELPARAM(this->width , this->height));
+ }
+ }
+#if USE_OVERLAY
+ this->overlay->update();
+#endif
+ }
+}
+
+LRESULT DSDisplay::handleEvents(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch(uMsg)
+ {
+ case WM_CREATE:
+ case WM_SIZE:
+ case WM_MOVE:
+ {
+ RECT rect = {0};
+ GetWindowRect(hWnd, &rect);
+ applyRatio(rect);
+
+#if defined(VMR9_WINDOWLESS)
+ this->graph->getWindowlessControl()->SetVideoPosition(&rect, &rect);
+#else
+ this->graph->getVideoWindow()->SetWindowPosition(this->left, this->top, this->width , this->height);
+#endif
+ }
+ break;
+
+ case WM_LBUTTONDBLCLK:
+ if(this->canFullscreen()){
+ this->setFullscreen(true);
+ }
+ break;
+
+ case WM_FULLSCREEN_SET:
+ if(this->canFullscreen()){
+ this->setFullscreen(!this->isFullscreen());
+ }
+ break;
+
+ case WM_LBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_KEYDOWN:
+ if(this->isFullscreen())
+ {
+#if USE_OVERLAY
+ // Re-Show overlay
+ this->overlay->show(OVERLAY_TIMEOUT * this->graph->getDisplayFps());
+#endif
+ }
+ break;
+
+ case WM_CHAR:
+ case WM_KEYUP:
+ if(this->isFullscreen() && (wParam == 0x1B || wParam == VK_ESCAPE))
+ {
+ // escape
+ this->setFullscreen(false);
+ }
+
+ break;
+
+ case WM_GRAPHNOTIFY:
+ {
+ long evCode;
+ LONG_PTR param1, param2;
+ HRESULT hr;
+ while (hr = this->graph->getMediaEvent()->GetEvent(&evCode, &param1, &param2, 0), SUCCEEDED(hr))
+ {
+ hr = this->graph->getMediaEvent()->FreeEventParams(evCode, param1, param2);
+
+ switch(evCode)
+ {
+ case EC_FULLSCREEN_LOST:
+#if USE_OVERLAY
+ this->overlay->show(0);
+#endif
+ break;
+ case EC_COMPLETE:
+ case EC_USERABORT:
+ default:
+ break;
+ }
+ }
+ }
+ break;
+
+#if defined(VMR9_WINDOWLESS)
+ case WM_DISPLAYCHANGE:
+ {
+ this->graph->getWindowlessControl()->DisplayModeChanged();
+ }
+ break;
+ case WM_PAINT:
+ {
+ RECT rect = {0};
+ GetWindowRect(hWnd, &rect);
+
+ PAINTSTRUCT ps;
+ HDC hdc = BeginPaint(hWnd, &ps);
+
+ this->graph->getWindowlessControl()->RepaintVideo(hWnd, hdc);
+
+ EndPaint(hWnd, &ps);
+ }
+ break;
+#endif
+
+ }
+
+ return bPluginFirefox ? DefWindowProc(hWnd, uMsg, wParam, lParam) : CallWindowProc(this->parentWindowProc, hWnd, uMsg, wParam, lParam);
+}
+
+void DSDisplay::hook()
+{
+ HRESULT hr;
+
+ if (!this->window){
+ return;
+ }
+
+ if(this->hooked){
+ return;
+ }
+ this->hooked = TRUE;
+
+ bool lock = (__directshow__Displays != NULL);
+
+ if(lock)
+ tsk_list_lock(__directshow__Displays);
+ {
+ // Gets the parent Window procedure
+#if defined(_WIN32_WCE)
+ // Workaround for bug in SetWindowLong, call twice the API
+ //this->parentWindowProc = (WNDPROC)SetWindowLong( this->window, GWL_WNDPROC, (LONG) __directshow__WndProcWindow );
+ //this->parentWindowProc = (WNDPROC)SetWindowLong( this->window, GWL_WNDPROC, (LONG) __directshow__WndProcWindow );
+ //__directshow__Displays[this->window] = this;
+#else
+ this->parentWindowProc = (WNDPROC) SetWindowLongPtr(this->window, GWLP_WNDPROC, (LONG_PTR) __directshow__WndProcWindow);
+ // Add this instance to the callback map
+ tsk_object_new(tdshow_display_def_t, this->window, this);
+#endif
+ }
+ if(lock)
+ tsk_list_unlock(__directshow__Displays);
+
+ RECT rect;
+ GetWindowRect(this->window, &rect);
+ applyRatio(rect);
+
+#if defined(VMR9_WINDOWLESS)
+ rect.left = 0;
+ rect.top = 0;
+ rect.right = this->width;
+ rect.bottom = this->height;
+
+ // TODO : Review
+ hr = this->graph->getWindowlessControl()->SetVideoClippingWindow(this->window);
+ hr = this->graph->getWindowlessControl()->SetBorderColor(RGB(0, 0, 128));
+ hr = this->graph->getWindowlessControl()->SetVideoPosition(NULL, &rect);
+#else
+ // TODO : Review the order
+ hr = this->graph->getVideoWindow()->put_Owner((OAHWND) this->window);
+ hr = this->graph->getVideoWindow()->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
+ hr = this->graph->getVideoWindow()->SetWindowPosition(this->left, this->top, this->width, this->height);
+ hr = this->graph->getVideoWindow()->put_MessageDrain((OAHWND) this->window);
+ hr = this->graph->getVideoWindow()->put_Visible(OATRUE);
+#endif
+
+ hr = this->graph->getMediaEvent()->SetNotifyWindow((OAHWND) this->window, WM_GRAPHNOTIFY, 0);
+}
+
+void DSDisplay::unhook()
+{
+ HRESULT hr;
+
+ if(!this->window){
+ return;
+ }
+
+ if(!this->hooked){
+ return;
+ }
+
+ hr = this->graph->getMediaEvent()->SetNotifyWindow(NULL, WM_GRAPHNOTIFY, 0);
+
+#if defined(VMR9_WINDOWLESS)
+ // TODO : Review
+ hr = this->graph->getWindowlessControl()->SetVideoClippingWindow(NULL);
+#else
+ // TODO : Review the order
+ hr = this->graph->getVideoWindow()->put_Visible(OAFALSE);
+ hr = this->graph->getVideoWindow()->put_MessageDrain((OAHWND) NULL);
+ hr = this->graph->getVideoWindow()->put_Owner((OAHWND) NULL);
+ hr = this->graph->getVideoWindow()->put_AutoShow(OAFALSE);
+#endif
+
+ bool lock = (__directshow__Displays != NULL);
+ if(lock)
+ tsk_list_lock(__directshow__Displays);
+ {
+ // Remove this instance from the callback map
+ tsk_list_remove_item_by_pred(__directshow__Displays, __pred_find_display_by_hwnd, &this->window);
+ // Restore parent Window procedure
+#if defined(_WIN32_WCE)
+ // Workaround for bug in SetWindowLong, call twice the API
+ //this->parentWindowProc = (WNDPROC)SetWindowLong( this->window, GWL_WNDPROC, (LONG) this->parentWindowProc );
+ //this->parentWindowProc = (WNDPROC)SetWindowLong( this->window, GWL_WNDPROC, (LONG) this->parentWindowProc );
+#else
+ SetWindowLongPtr(this->window, GWLP_WNDPROC, (LONG_PTR) this->parentWindowProc);
+#endif
+ }
+ if(lock)
+ tsk_list_unlock(__directshow__Displays);
+
+ this->hooked = FALSE;
+}
+
+
+
+
+
+
+
+
+
+
+
+//=================================================================================================
+// String object definition
+//
+static tsk_object_t* tdshow_display_ctor(tsk_object_t * self, va_list * app)
+{
+ tdshow_display_t *display = (tdshow_display_t *)self;
+
+ if(display){
+ display->hwnd = va_arg(*app, HWND);
+ display->display = va_arg(*app, DSDisplay*);
+
+ if(!__directshow__Displays){
+ __directshow__Displays = tsk_list_create();
+ }
+ tsk_list_push_back_data(__directshow__Displays, (void**)&display);
+ }
+
+ return self;
+}
+
+static tsk_object_t* tdshow_display_dtor(tsk_object_t * self)
+{
+ tdshow_display_t *display = (tdshow_display_t *)self;
+ if(display){
+ if(__directshow__Displays){
+ tsk_list_remove_item_by_data(__directshow__Displays, display);
+ //if(TSK_LIST_IS_EMPTY(__directshow__Displays)){
+ // TSK_OBJECT_SAFE_FREE(__directshow__Displays);
+ //}
+ }
+ }
+
+ return self;
+}
+
+static int tdshow_display_cmp(const tsk_object_t *_d1, const tsk_object_t *_d2)
+{
+ const tdshow_display_t *d1 = (const tdshow_display_t *)_d1;
+ const tdshow_display_t *d2 = (const tdshow_display_t *)_d2;
+
+ if(d1 && d2){
+ int ret = 0;
+ tsk_subsat_int32_ptr(d1->hwnd, d2->hwnd, &ret);
+ return ret;
+ }
+ else if(!d1 && !d2) return 0;
+ else return -1;
+}
+
+static const tsk_object_def_t tdshow_display_def_s =
+{
+ sizeof(tdshow_display_t),
+ tdshow_display_ctor,
+ tdshow_display_dtor,
+ tdshow_display_cmp,
+};
+extern const tsk_object_def_t *tdshow_display_def_t = &tdshow_display_def_s;
diff --git a/plugins/pluginDirectShow/internals/DSDisplay.h b/plugins/pluginDirectShow/internals/DSDisplay.h
new file mode 100644
index 0000000..b2985ef
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/DSDisplay.h
@@ -0,0 +1,84 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+#ifndef PLUGIN_DSHOW_DIRECTSHOW_DISPLAY_H
+#define PLUGIN_DSHOW_DIRECTSHOW_DISPLAY_H
+
+#include "plugin_dshow_config.h"
+
+#include "internals/DSDisplayGraph.h"
+#include "internals/DSDisplayOverlay.h"
+
+#define WM_FULLSCREEN_SET (WM_USER + 401)
+
+class DSDisplay
+{
+public:
+ DSDisplay(HRESULT *hr);
+ virtual ~DSDisplay();
+
+ virtual void attach(INT64 parent);
+ virtual void attach(void *parent);
+ virtual void detach(void *parent);
+ virtual void detach();
+ virtual bool isAttached();
+
+ virtual void start();
+ virtual void pause();
+ virtual void stop();
+
+ virtual int getWidth();
+ virtual int getHeight();
+ virtual void setSize(int w, int h);
+
+ virtual bool isFullscreen();
+ virtual void setFullscreen(bool value);
+ virtual void setPluginFirefox(bool value);
+
+ virtual bool canFullscreen();
+
+ virtual void setFps(int fps_);
+
+ virtual void handleVideoFrame(const void* data, int w, int h);
+
+ LRESULT handleEvents(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+private:
+ void hook();
+ void unhook();
+ void applyRatio(RECT rect);
+
+private:
+ DSDisplayGraph *graph;
+ DSDisplayOverlay *overlay;
+
+ int fps;
+ int left, top, width, height, imgWidth, imgHeight;
+
+ bool bPluginFirefox;
+ bool fullscreen;
+ HWND window;
+ WNDPROC parentWindowProc;
+
+ bool hooked;
+};
+
+#endif
diff --git a/plugins/pluginDirectShow/internals/DSDisplayGraph.cxx b/plugins/pluginDirectShow/internals/DSDisplayGraph.cxx
new file mode 100644
index 0000000..b2da43b
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/DSDisplayGraph.cxx
@@ -0,0 +1,345 @@
+/* Copyright (C) 2011-2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#if defined(VMR9)
+#define DIRECT3D_VERSION 0x0900
+#endif
+
+#include "internals/DSDisplayGraph.h"
+#include "internals/DSUtils.h"
+#include "internals/DSOutputFilter.h"
+
+#include "tsk_debug.h"
+
+#include <iostream>
+
+using namespace std;
+
+DSDisplayGraph::DSDisplayGraph(HRESULT *hr)
+{
+ this->running = FALSE;
+ this->paused = FALSE;
+ this->fps = 15;
+
+ this->graphBuilder = NULL;
+
+ this->sourceFilter = NULL;
+ this->colorspaceConverterFilter = NULL;
+ this->videoRendererFilter = NULL;
+
+ this->mediaController = NULL;
+ this->mediaEvent = NULL;
+ this->videoWindow = NULL;
+
+#if defined(VMR) ||defined(VMR9) || defined(VMR9_WINDOWLESS)
+ this->mixerBitmap = NULL;
+ this->filterConfig = NULL;
+#endif
+
+#if defined(VMR9_WINDOWLESS)
+ this->windowlessControl = NULL;
+#endif
+
+ *hr = this->createDisplayGraph();
+ if (FAILED(*hr)) return;
+
+ *hr = this->connect();
+ if (FAILED(*hr)) return;
+}
+
+DSDisplayGraph::~DSDisplayGraph()
+{
+ this->disconnect();
+
+#if defined(VMR9_WINDOWLESS)
+ SAFE_RELEASE(this->windowlessControl);
+#endif
+
+#if defined(VMR) ||defined(VMR9) || defined(VMR9_WINDOWLESS)
+ SAFE_RELEASE(this->filterConfig);
+ SAFE_RELEASE(this->mixerBitmap);
+#endif
+
+ SAFE_RELEASE(this->videoWindow);
+ SAFE_RELEASE(this->mediaEvent);
+ SAFE_RELEASE(this->mediaController);
+
+ SAFE_RELEASE(this->colorspaceConverterFilter);
+ SAFE_RELEASE(this->videoRendererFilter);
+ //SAFE_RELEASE(this->sourceFilter);
+
+ SAFE_RELEASE(this->graphBuilder);
+}
+
+void DSDisplayGraph::setDisplayFps(int fps_)
+{
+ this->fps = fps_;
+ if(this->sourceFilter){
+ this->sourceFilter->setFps(fps_);
+ }
+}
+
+bool DSDisplayGraph::getImageFormat(UINT &width, UINT &height)
+{
+ if(this->sourceFilter){
+ return this->sourceFilter->getImageFormat(width, height);
+ }
+ return false;
+}
+
+bool DSDisplayGraph::setImageFormat(UINT width, UINT height)
+{
+ bool ret = true;
+ if(this->sourceFilter){
+ UINT w=width, h = height;
+ if(this->sourceFilter->getImageFormat(w, h)){
+ if(w!= width || h!=height){ // Image format has changed
+ bool reconnect = this->connected; // IMPORTANT: Must reconnect all elements
+ HRESULT hr;
+ if(reconnect){
+ if((hr = this->disconnect()) != S_OK){
+ return false;
+ }
+ }
+ ret = (this->sourceFilter->setImageFormat(width, height) == S_OK);
+ if(reconnect){
+ if((hr = this->connect())){
+ return false;
+ }
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+HRESULT DSDisplayGraph::connect()
+{
+ HRESULT hr;
+
+ if((hr = ConnectFilters(this->graphBuilder, this->sourceFilter, this->colorspaceConverterFilter)) != S_OK){
+ TSK_DEBUG_ERROR("Failed to connect sourcefilter with the colorspace");
+ return hr;
+ }
+ if((hr = ConnectFilters(this->graphBuilder, this->colorspaceConverterFilter, this->videoRendererFilter)) != S_OK){
+ TSK_DEBUG_ERROR("Failed to connect colorspace with the videorenderer");
+ return hr;
+ }
+
+ this->connected = true;
+ return S_OK;
+}
+
+HRESULT DSDisplayGraph::disconnect()
+{
+ HRESULT hr;
+
+ if((hr = DisconnectFilters(this->graphBuilder, this->sourceFilter, this->colorspaceConverterFilter)) != S_OK){
+ TSK_DEBUG_ERROR("Failed to disconnect sourcefilter with the colorspace");
+ return hr;
+ }
+ if((hr = DisconnectFilters(this->graphBuilder, this->colorspaceConverterFilter, this->videoRendererFilter)) != S_OK){
+ TSK_DEBUG_ERROR("Failed to connect colorspace with the videorenderer");
+ return hr;
+ }
+
+ this->connected = false;
+ return S_OK;
+}
+
+HRESULT DSDisplayGraph::start()
+{
+ HRESULT hr;
+ this->running = true;
+ this->sourceFilter->reset();
+
+ hr = this->mediaController->Run();
+ if (!SUCCEEDED(hr)){
+ TSK_DEBUG_ERROR("DSDisplayGraph::mediaController->Run() has failed with %ld", hr);
+ }
+ return hr;
+}
+
+HRESULT DSDisplayGraph::pause()
+{
+ HRESULT hr = S_OK;
+ if(isRunning() && !isPaused()){
+ hr = this->mediaController->Pause();
+ if(SUCCEEDED(hr)){
+ this->paused = true;
+ }
+ }
+ return hr;
+}
+
+HRESULT DSDisplayGraph::stop()
+{
+ HRESULT hr;
+
+ hr = this->mediaController->Pause();
+ if (hr == S_FALSE){
+ TSK_DEBUG_ERROR("DSDisplayGraph::mediaController->Pause() has failed with %ld. Waiting for transition.", hr);
+ FILTER_STATE pfs;
+ hr = this->mediaController->GetState(2500, (OAFilterState*) &pfs);
+ }
+
+ hr = this->mediaController->Stop();
+ if (!SUCCEEDED(hr)){
+ TSK_DEBUG_ERROR("DSDisplayGraph::mediaController->Stop() has failed with %ld", hr);
+ }
+
+ this->running = false;
+ this->paused = false;
+
+ return hr;
+}
+
+bool DSDisplayGraph::isRunning()
+{
+ return this->running;
+}
+
+bool DSDisplayGraph::isPaused()
+{
+ return this->paused;
+}
+
+void DSDisplayGraph::handleFrame(const void* data, int w, int h)
+{
+ HRESULT hr;
+
+ if(!this->sourceFilter){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return;
+ }
+
+ if(!data || !this->running){
+ this->sourceFilter->setBuffer(NULL, (w*h*3));
+ return;
+ }
+
+ hr = this->sourceFilter->setImageFormat(w, h);
+ if (hr == S_OK){
+ this->stop();
+
+ this->disconnect();
+ this->connect();
+
+ this->start();
+ }
+
+ this->sourceFilter->setBuffer((void*)data, (w*h*3));
+}
+
+HRESULT DSDisplayGraph::createDisplayGraph()
+{
+ HRESULT hr;
+
+ // Create the graph builder
+ hr = COCREATE(CLSID_FilterGraph, IID_IGraphBuilder, this->graphBuilder);
+ if(FAILED(hr)) return hr;
+
+
+ // Create my custom filter
+ LPUNKNOWN pUnk = NULL;
+ this->sourceFilter = new DSOutputFilter(pUnk, &hr /*, this*/);
+ if(FAILED(hr) || this->sourceFilter == NULL) return hr;
+
+ // Create the color space convertor filter
+ hr = COCREATE(CLSID_Colour, IID_IBaseFilter, this->colorspaceConverterFilter);
+ if(FAILED(hr)) return hr;
+
+#if defined(VMR)
+ // Create the video mixing renderer based on Direct X
+ hr = COCREATE(CLSID_VideoMixingRenderer, IID_IBaseFilter, this->videoRendererFilter);
+ if(FAILED(hr)) return hr;
+#elif defined(VMR9) || defined(VMR9_WINDOWLESS)
+ // Create the video mixing renderer based on Direct X 9.0
+ hr = COCREATE(CLSID_VideoMixingRenderer9, IID_IBaseFilter, this->videoRendererFilter);
+ if(FAILED(hr)) return hr;
+#else
+ // Create the video renderer
+ hr = COCREATE(CLSID_VideoRenderer, IID_IBaseFilter, this->videoRendererFilter);
+ if(FAILED(hr)) return hr;
+#endif
+
+
+ // Add dource filter to the graph
+ hr = this->graphBuilder->AddFilter(this->sourceFilter, FILTER_OUTPUT);
+ if(FAILED(hr)) return hr;
+
+ // Add the color space convertor to the graph
+ hr = this->graphBuilder->AddFilter(this->colorspaceConverterFilter, FILTER_COLORSPACE_CONVERTOR);
+ if(FAILED(hr)) return hr;
+
+ // Add video renderer to the graph
+ hr = this->graphBuilder->AddFilter(this->videoRendererFilter, FILTER_VIDEO_RENDERER);
+ if(FAILED(hr)) return hr;
+
+
+ // Find media control
+ hr = QUERY(this->graphBuilder, IID_IMediaControl, this->mediaController);
+ if(FAILED(hr)) return hr;
+
+ // Find media event
+ hr = QUERY(this->graphBuilder, IID_IMediaEventEx, this->mediaEvent);
+ if(FAILED(hr)) return hr;
+ // hr = this->mediaEvent->SetNotifyFlags(AM_MEDIAEVENT_NONOTIFY);
+
+
+#if defined(VMR)
+ // Find the bitmap mixer (Direct X)
+ hr = QUERY(this->videoRendererFilter, IID_IVMRMixerBitmap, this->mixerBitmap);
+ if(FAILED(hr)) return hr;
+
+ // Find the bitmap configurer (Direct X)
+ hr = QUERY(this->videoRendererFilter, IID_IVMRFilterConfig, this->filterConfig);
+ if(FAILED(hr)) return hr;
+
+ // Set the number of streams (Direct X)
+ hr = this->filterConfig->SetNumberOfStreams(1);
+ if(FAILED(hr)) return hr;
+#elif defined(VMR9) || defined(VMR9_WINDOWLESS)
+ // Find the bitmap mixer (Direct X 9.0)
+ hr = QUERY(this->videoRendererFilter, IID_IVMRMixerBitmap9, this->mixerBitmap);
+ if(FAILED(hr)) return hr;
+
+ // Find the bitmap configurer (Direct X 9.0)
+ hr = QUERY(this->videoRendererFilter, IID_IVMRFilterConfig9, this->filterConfig);
+ if(FAILED(hr)) return hr;
+
+ // Set the number of streams (Direct X 9.0)
+ hr = this->filterConfig->SetNumberOfStreams(1);
+ if(FAILED(hr)) return hr;
+#endif
+
+#if defined(VMR9_WINDOWLESS)
+ // Set the rendering mode (Direct X 9.0)
+ hr = this->filterConfig->SetRenderingMode(VMR9Mode_Windowless);
+ if(FAILED(hr)) return hr;
+
+ // Find the windowless control (Direct X 9.0)
+ hr = QUERY(this->videoRendererFilter, IID_IVMRWindowlessControl9, this->windowlessControl);
+ if(FAILED(hr)) return hr;
+#else
+ // Find IVideoWindow interface
+ hr = QUERY(this->graphBuilder, IID_IVideoWindow, this->videoWindow);
+ if(FAILED(hr)) return hr;
+#endif
+
+ return hr;
+}
diff --git a/plugins/pluginDirectShow/internals/DSDisplayGraph.h b/plugins/pluginDirectShow/internals/DSDisplayGraph.h
new file mode 100644
index 0000000..c9080fe
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/DSDisplayGraph.h
@@ -0,0 +1,110 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+#ifndef PLUGIN_DSHOW_DSDISPLAYGRAPH_H
+#define PLUGIN_DSHOW_DSDISPLAYGRAPH_H
+
+#include "plugin_dshow_config.h"
+
+#include <control.h>
+
+#include "internals/VideoFrame.h"
+#include "internals/DSOutputFilter.h"
+#include "internals/DSDisplayOverlay.h"
+
+#if defined(VMR9) || defined(VMR9_WINDOWLESS)
+#include <D3D9.h>
+#include <vmr9.h>
+#endif
+
+
+class DSDisplayGraph
+{
+public:
+ DSDisplayGraph(HRESULT *hr);
+ virtual ~DSDisplayGraph();
+
+ int getDisplayFps() { return this->fps; };
+ void setDisplayFps(int fps_);
+
+ bool getImageFormat(UINT &width, UINT &height);
+ bool setImageFormat(UINT width, UINT height);
+
+ HRESULT connect();
+ HRESULT disconnect();
+
+ HRESULT start();
+ HRESULT pause();
+ HRESULT stop();
+ bool isRunning();
+ bool isPaused();
+
+ IMediaEventEx *getMediaEvent() { return this->mediaEvent; };
+ IVideoWindow *getVideoWindow() { return this->videoWindow; };
+ DSOutputFilter *getSourceFilter() { return this->sourceFilter; };
+
+#if defined(VMR)
+ IVMRMixerBitmap *getMixerBitmap() { return this->mixerBitmap; };
+#elif defined(VMR9)
+ IVMRMixerBitmap9 *getMixerBitmap() { return this->mixerBitmap; };
+#elif defined(VMR9_WINDOWLESS)
+ IVMRMixerBitmap9 *getMixerBitmap() { return this->mixerBitmap; };
+ IVMRMixerControl9 *getMixerControl() { return this->mixerControl; };
+ IVMRWindowlessControl9 *getWindowlessControl() { return this->windowlessControl; };
+#endif
+
+ void handleFrame(const void* data, int w, int h);
+
+private:
+ HRESULT createDisplayGraph();
+
+private:
+ IGraphBuilder *graphBuilder;
+
+ DSOutputFilter *sourceFilter;
+ IBaseFilter *colorspaceConverterFilter;
+ IBaseFilter *videoRendererFilter;
+
+ IMediaControl *mediaController;
+ IMediaEventEx *mediaEvent;
+ IVideoWindow *videoWindow;
+
+#if defined(VMR)
+ IVMRMixerBitmap *mixerBitmap;
+ IVMRFilterConfig *filterConfig;
+#elif defined(VMR9)
+ IVMRMixerBitmap9 *mixerBitmap;
+ IVMRMixerControl9 *mixerControl;
+ IVMRFilterConfig9 *filterConfig;
+#elif defined(VMR9_WINDOWLESS)
+ IVMRMixerBitmap9 *mixerBitmap;
+ IVMRMixerControl9 *mixerControl;
+ IVMRFilterConfig9 *filterConfig;
+ IVMRWindowlessControl9 *windowlessControl;
+#endif
+
+ bool connected;
+ bool running;
+ bool paused;
+ int fps;
+};
+
+#endif
diff --git a/plugins/pluginDirectShow/internals/DSDisplayOverlay.VMR.cxx b/plugins/pluginDirectShow/internals/DSDisplayOverlay.VMR.cxx
new file mode 100644
index 0000000..dacea84
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/DSDisplayOverlay.VMR.cxx
@@ -0,0 +1,179 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+#if defined(VMR)
+
+#include "internals/DSDisplayOverlay.h"
+#include "internals/DSDisplayGraph.h"
+#include "internals/DSUtils.h"
+#include "../../resource.h"
+
+using namespace std;
+
+#define ALPHA_VALUE_START 0.8f
+#define ALPHA_VALUE_STOP 0.0f
+
+
+// Hack to get module of the current code
+// Only works with Microsoft Linker and could break in the future
+EXTERN_C IMAGE_DOS_HEADER __ImageBase;
+
+
+DSDisplayOverlay::DSDisplayOverlay()
+{
+ this->window = NULL;
+ this->hdcBmp = NULL;
+ this->hbmOld = NULL;
+}
+
+DSDisplayOverlay::~DSDisplayOverlay()
+{
+}
+
+void DSDisplayOverlay::attach(HWND parent, DSDisplayGraph *graph)
+{
+ HRESULT hr;
+
+ // Gets the handle of the parent and the graph
+ this->window = parent;
+ this->displayGraph = graph;
+
+ if (this->window)
+ {
+ // Hack to get module of the current code
+ TCHAR *modulePath = (TCHAR *) calloc(255, sizeof(TCHAR));
+ GetModuleFileName((HINSTANCE)&__ImageBase, modulePath, 255);
+ HMODULE module = GetModuleHandle(modulePath);
+ delete[] modulePath;
+ if (!module)
+ {
+ cout << "Failed to get current module";
+ return;
+ }
+
+ HBITMAP bitmap = LoadBitmap(module, MAKEINTRESOURCE(IDB_BITMAP_OVERLAY));
+ if (!bitmap)
+ {
+ cout << "Failed to load overlay bitmap" << endl;
+ return;
+ }
+
+ RECT rect;
+ hr = GetWindowRect(this->window, &rect);
+ if (FAILED(hr))
+ {
+ cout << "Failed to get window size" << endl;
+ return;
+ }
+
+ BITMAP bm;
+ HDC hdc = GetDC(this->window);
+ this->hdcBmp = CreateCompatibleDC(hdc);
+ ReleaseDC(this->window, hdc);
+
+ GetObject(bitmap, sizeof(bm), &bm);
+ this->hbmOld= (HBITMAP) SelectObject(this->hdcBmp, bitmap);
+
+ ZeroMemory(&this->alphaBitmap, sizeof(VMRALPHABITMAP));
+ this->alphaBitmap.dwFlags = VMRBITMAP_HDC | VMRBITMAP_SRCCOLORKEY;
+ this->alphaBitmap.hdc = this->hdcBmp;
+ this->alphaBitmap.clrSrcKey = 0x00FF00FF;
+ // Source rectangle
+ this->alphaBitmap.rSrc.left = 0;
+ this->alphaBitmap.rSrc.top = 0;
+ this->alphaBitmap.rSrc.right = bm.bmWidth;
+ this->alphaBitmap.rSrc.bottom = bm.bmHeight;
+ // Destination rectangle
+ this->alphaBitmap.rDest.left = (rect.right - rect.left - bm.bmWidth) / 2.0;
+ this->alphaBitmap.rDest.top = (rect.bottom - rect.top - bm.bmHeight) / 2.0;
+ this->alphaBitmap.rDest.right = this->alphaBitmap.rDest.left + bm.bmWidth;
+ this->alphaBitmap.rDest.bottom = this->alphaBitmap.rDest.top + bm.bmHeight;
+ this->alphaBitmap.rDest.left /= (rect.right - rect.left);
+ this->alphaBitmap.rDest.top /= (rect.bottom - rect.top);
+ this->alphaBitmap.rDest.right /= (rect.right - rect.left);
+ this->alphaBitmap.rDest.bottom /= (rect.bottom - rect.top);
+ // Alpha value for start
+ this->alphaBitmap.fAlpha = ALPHA_VALUE_START;
+
+ }
+}
+
+void DSDisplayOverlay::detach()
+{
+ // Clean up
+ DeleteObject(SelectObject(this->hdcBmp, this->hbmOld));
+ DeleteDC(this->hdcBmp);
+
+ this->hdcBmp = NULL;
+ this->hbmOld = NULL;
+ this->displayGraph = NULL;
+ this->window = NULL;
+}
+
+void DSDisplayOverlay::show(int value)
+{
+ // Store the ticks to count down
+ this->ticks = value;
+
+ // Compute alpha value decrement
+ this->alphaStep = (this->ticks > 0) ? ((ALPHA_VALUE_START - ALPHA_VALUE_STOP) / this->ticks) : 0;
+ this->alphaBitmap.fAlpha = ALPHA_VALUE_START;
+
+ this->internalUpdate();
+}
+
+void DSDisplayOverlay::update()
+{
+ if (this->displayGraph && (this->ticks > 0))
+ {
+ this->ticks--;
+
+ // Be sure alpha is in 0.0 .. 1.0 range.
+ float value = this->alphaBitmap.fAlpha;
+ value -= this->alphaStep;
+ this->alphaBitmap.fAlpha = (value >= 0.0f) ? value : 0.0f;
+
+ this->internalUpdate();
+ }
+}
+
+void DSDisplayOverlay::internalUpdate()
+{
+ HRESULT hr;
+
+ if (this->ticks > 0)
+ {
+ this->alphaBitmap.dwFlags = VMRBITMAP_HDC | VMRBITMAP_SRCCOLORKEY;
+ }
+ else
+ {
+ this->alphaBitmap.dwFlags = VMRBITMAP_DISABLE;
+ }
+
+ hr = this->displayGraph->getMixerBitmap()->SetAlphaBitmap(&this->alphaBitmap);
+ if (FAILED(hr))
+ {
+ cout << "Failed to mix overylay (" << hr << ")" << endl;
+ return;
+ }
+}
+
+#endif
diff --git a/plugins/pluginDirectShow/internals/DSDisplayOverlay.VMR9.cxx b/plugins/pluginDirectShow/internals/DSDisplayOverlay.VMR9.cxx
new file mode 100644
index 0000000..972945f
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/DSDisplayOverlay.VMR9.cxx
@@ -0,0 +1,207 @@
+/* Copyright (C) 2011-2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#if defined(VMR9) || defined(VMR9_WINDOWLESS)
+
+#define DIRECT3D_VERSION 0x0900
+
+#include <internals/DSDisplayOverlay.h>
+#include <internals/DSDisplayGraph.h>
+#include <internals/DSUtils.h>
+
+using namespace std;
+
+#define FILENAME _T("Overlay.png")
+#define ALPHA_VALUE_START 0.8f
+#define ALPHA_VALUE_STOP 0.0f
+
+
+DSDisplayOverlay::DSDisplayOverlay()
+{
+ this->window = NULL;
+ this->direct3DDevice = NULL;
+ this->direct3DSurface = NULL;
+
+ this->direct3D = Direct3DCreate9(D3D_SDK_VERSION);
+ if (!this->direct3D)
+ {
+ cout << "Cannot create Direct3D environment" << endl;
+ return;
+ }
+}
+
+DSDisplayOverlay::~DSDisplayOverlay()
+{
+ SAFE_RELEASE(this->direct3D);
+}
+
+void DSDisplayOverlay::attach(HWND parent, DSDisplayGraph *graph)
+{
+ HRESULT hr;
+
+ // Gets the handle of the parent and the graph
+ this->window = parent;
+ this->displayGraph = graph;
+
+ if (this->window)
+ {
+ D3DPRESENT_PARAMETERS d3dpp;
+ ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS));
+ d3dpp.Windowed = TRUE;
+ d3dpp.SwapEffect = D3DSWAPEFFECT_COPY;
+
+ hr = this->direct3D->CreateDevice(
+ D3DADAPTER_DEFAULT,
+ D3DDEVTYPE_HAL,
+ this->window,
+ D3DCREATE_SOFTWARE_VERTEXPROCESSING,
+ &d3dpp,
+ &this->direct3DDevice);
+ if (FAILED(hr))
+ {
+ cout << "Cannot create Direct3D device" << endl;
+ return;
+ }
+
+ ZeroMemory(&this->overlayInfo, sizeof(D3DXIMAGE_INFO));
+ hr = D3DXGetImageInfoFromFile(FILENAME, &this->overlayInfo);
+ if (FAILED(hr))
+ {
+ cout << "Cannot stat overlay file" << endl;
+ return;
+ }
+
+ hr = this->direct3DDevice->CreateOffscreenPlainSurface(
+ this->overlayInfo.Width,
+ this->overlayInfo.Height,
+ D3DFMT_A8R8G8B8,
+ D3DPOOL_SYSTEMMEM,
+ &this->direct3DSurface,
+ NULL);
+ if (FAILED(hr))
+ {
+ cout << "Cannot create Direct3D surface" << endl;
+ return;
+ }
+
+ D3DCOLOR alphaKey = 0xFF000000;
+
+ hr = D3DXLoadSurfaceFromFile(this->direct3DSurface,
+ NULL,
+ NULL,
+ FILENAME,
+ NULL,
+ D3DX_FILTER_NONE,
+ alphaKey,
+ &this->overlayInfo);
+ if (FAILED(hr))
+ {
+ cout << "Cannot load overlay file" << endl;
+ return;
+ }
+
+ D3DVIEWPORT9 viewport;
+ ZeroMemory(&viewport, sizeof(D3DVIEWPORT9));
+
+ hr= this->direct3DDevice->GetViewport(&viewport);
+ if (FAILED(hr))
+ {
+ cout << "Cannot get view port" << endl;
+ return;
+ }
+
+ ZeroMemory(&this->alphaBitmap, sizeof(VMR9AlphaBitmap));
+ this->alphaBitmap.dwFlags = VMR9AlphaBitmap_EntireDDS;
+ this->alphaBitmap.hdc = NULL;
+ this->alphaBitmap.pDDS = this->direct3DSurface;
+ // Source rectangle
+ this->alphaBitmap.rSrc.left = 0;
+ this->alphaBitmap.rSrc.top = 0;
+ this->alphaBitmap.rSrc.right = this->overlayInfo.Width;
+ this->alphaBitmap.rSrc.bottom = this->overlayInfo.Height;
+ // Destination rectangle
+ this->alphaBitmap.rDest.left = (viewport.Width - this->overlayInfo.Width) / 2.0;
+ this->alphaBitmap.rDest.top = (viewport.Height - this->overlayInfo.Height) / 2.0;
+ this->alphaBitmap.rDest.right = this->alphaBitmap.rDest.left + this->overlayInfo.Width;
+ this->alphaBitmap.rDest.bottom = this->alphaBitmap.rDest.top + this->overlayInfo.Height;
+ this->alphaBitmap.rDest.left /= viewport.Width;
+ this->alphaBitmap.rDest.top /= viewport.Height;
+ this->alphaBitmap.rDest.right /= viewport.Width;
+ this->alphaBitmap.rDest.bottom /= viewport.Height;
+ // Alpha value for start
+ this->alphaBitmap.fAlpha = ALPHA_VALUE_START;
+ }
+}
+
+void DSDisplayOverlay::detach()
+{
+ SAFE_RELEASE(this->direct3DSurface);
+ SAFE_RELEASE(this->direct3DDevice);
+
+ this->displayGraph = NULL;
+ this->window = NULL;
+}
+
+void DSDisplayOverlay::show(int value)
+{
+ // Store the ticks to count down
+ this->ticks = value;
+
+ // Compute alpha value decrement
+ this->alphaStep = (this->ticks > 0) ? ((ALPHA_VALUE_START - ALPHA_VALUE_STOP) / this->ticks) : 0;
+ this->alphaBitmap.fAlpha = ALPHA_VALUE_START;
+
+ this->internalUpdate();
+}
+
+void DSDisplayOverlay::update()
+{
+ if (this->displayGraph && (this->ticks > 0))
+ {
+ this->ticks--;
+
+ // Be sure alpha is in 0.0 .. 1.0 range.
+ float value = this->alphaBitmap.fAlpha;
+ value -= this->alphaStep;
+ this->alphaBitmap.fAlpha = (value >= 0.0f) ? value : 0.0f;
+
+ this->internalUpdate();
+ }
+}
+
+void DSDisplayOverlay::internalUpdate()
+{
+ HRESULT hr;
+
+ if (this->ticks > 0)
+ {
+ this->alphaBitmap.dwFlags = VMR9AlphaBitmap_EntireDDS;
+ }
+ else
+ {
+ this->alphaBitmap.dwFlags = VMR9AlphaBitmap_Disable;
+ }
+
+ hr = this->displayGraph->getMixerBitmap()->SetAlphaBitmap(&this->alphaBitmap);
+ if (FAILED(hr))
+ {
+ cout << "Failed to mix overylay (" << hr << ")" << endl;
+ return;
+ }
+}
+
+#endif
diff --git a/plugins/pluginDirectShow/internals/DSDisplayOverlay.cxx b/plugins/pluginDirectShow/internals/DSDisplayOverlay.cxx
new file mode 100644
index 0000000..eb355c4
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/DSDisplayOverlay.cxx
@@ -0,0 +1,67 @@
+/* Copyright (C) 2011-2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#if !defined(VMR) && !defined(VMR9) && !defined(VMR9_WINDOWLESS)
+
+#include "internals/DSDisplayOverlay.h"
+#include "internals/DSDisplayGraph.h"
+
+#include <iostream>
+
+using namespace std;
+
+DSDisplayOverlay::DSDisplayOverlay()
+{
+}
+
+DSDisplayOverlay::~DSDisplayOverlay()
+{
+}
+
+void DSDisplayOverlay::attach(HWND parent, DSDisplayGraph *graph)
+{
+ this->displayGraph = graph;
+}
+
+void DSDisplayOverlay::detach()
+{
+ this->displayGraph = NULL;
+}
+
+void DSDisplayOverlay::show(int value)
+{
+ // Store the ticks to count down
+ this->ticks = value;
+
+ this->internalUpdate();
+}
+
+void DSDisplayOverlay::update()
+{
+ if (this->displayGraph && (this->ticks > 0))
+ {
+ this->ticks--;
+ this->internalUpdate();
+ }
+}
+
+void DSDisplayOverlay::internalUpdate()
+{
+ this->displayGraph->getSourceFilter()->showOverlay(this->ticks);
+}
+
+#endif
diff --git a/plugins/pluginDirectShow/internals/DSDisplayOverlay.h b/plugins/pluginDirectShow/internals/DSDisplayOverlay.h
new file mode 100644
index 0000000..0db887d
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/DSDisplayOverlay.h
@@ -0,0 +1,68 @@
+/* Copyright (C) 2011-2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#ifndef PLUGIN_DSHOW_DSDISPLAYOVERLAY_H
+#define PLUGIN_DSHOW_DSDISPLAYOVERLAY_H
+
+#include "plugin_dshow_config.h"
+#include <strmif.h>
+
+#if defined(VMR9) || defined(VMR9_WINDOWLESS)
+#include <D3D9.h>
+#include <D3Dx9.h>
+#include <vmr9.h>
+#endif
+
+class DSDisplayGraph;
+
+class DSDisplayOverlay
+{
+public:
+ DSDisplayOverlay();
+ virtual ~DSDisplayOverlay();
+
+ void attach(HWND parent, DSDisplayGraph *graph);
+ void detach();
+
+ void show(int value);
+ void update();
+
+private:
+ void internalUpdate();
+
+private:
+ HWND window;
+
+ DSDisplayGraph *displayGraph;
+ int ticks;
+
+#if defined(VMR)
+ HDC hdcBmp;
+ HBITMAP hbmOld;
+ VMRALPHABITMAP alphaBitmap;
+ float alphaStep;
+#elif defined(VMR9) || defined(VMR9_WINDOWLESS)
+ IDirect3D9 *direct3D;
+ IDirect3DDevice9 *direct3DDevice;
+ IDirect3DSurface9 *direct3DSurface;
+ D3DXIMAGE_INFO overlayInfo;
+ VMR9AlphaBitmap alphaBitmap;
+ float alphaStep;
+#endif
+};
+
+#endif
diff --git a/plugins/pluginDirectShow/internals/DSFrameRateFilter.cxx b/plugins/pluginDirectShow/internals/DSFrameRateFilter.cxx
new file mode 100644
index 0000000..cbf2a0a
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/DSFrameRateFilter.cxx
@@ -0,0 +1,120 @@
+/* Copyright (C) 2011-2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#include "internals/DSFrameRateFilter.h"
+
+#include <iostream>
+#include <string>
+
+using namespace std;
+
+#define FPS_INPUT 30
+#define FPS_OUTPUT 5
+
+// {7F9F08CF-139F-40b2-A283-01C4EC26A452}
+TDSHOW_DEFINE_GUID(CLSID_DSFrameRateFilter,
+0x7f9f08cf, 0x139f, 0x40b2, 0xa2, 0x83, 0x1, 0xc4, 0xec, 0x26, 0xa4, 0x52);
+
+DSFrameRateFilter::DSFrameRateFilter(TCHAR *tszName, LPUNKNOWN punk, HRESULT *phr)
+:CTransInPlaceFilter (tszName, punk, CLSID_DSFrameRateFilter, phr)
+{
+ this->m_rtFrameLength = (10000000)/FPS_OUTPUT;
+
+ this->m_inputFps = FPS_INPUT;
+ this->m_outputFps = FPS_OUTPUT;
+
+ this->m_iFrameNumber = 0;
+ this->m_progress = 0;
+ this->m_bProcessFrame = true;
+}
+
+DSFrameRateFilter::~DSFrameRateFilter()
+{
+}
+
+HRESULT DSFrameRateFilter::SetFps(int inputFps, int outputFps)
+{
+ if(inputFps <= 0 || outputFps <= 0)
+ {
+ return E_FAIL;
+ }
+
+ // Stop prcessing
+ this->m_bProcessFrame = false;
+
+ if (inputFps < outputFps) {
+ this->m_inputFps = this->m_outputFps = inputFps;
+ }
+ else {
+ this->m_outputFps = outputFps;
+ this->m_inputFps = inputFps;
+ }
+
+ // Restart processing
+ this->m_iFrameNumber = 0;
+ this->m_progress = 0;
+ this->m_bProcessFrame = true;
+
+ return S_OK;
+}
+
+HRESULT DSFrameRateFilter::Transform(IMediaSample *pSample)
+{
+ if(!this->m_bProcessFrame) return S_FALSE;
+
+ CheckPointer(pSample, E_POINTER);
+
+ HRESULT hr = S_OK;
+ HRESULT ret = S_FALSE;
+
+ pSample->SetTime(NULL, NULL);
+
+ // Drop frame?
+ if (this->m_iFrameNumber == 0) {
+ ret = S_OK;
+ }
+ else if (this->m_progress >= this->m_inputFps) {
+ this->m_progress -= this->m_inputFps;
+ ret = S_OK;
+ }
+
+ // Mark frame as accepted
+ if (ret == S_OK) {
+ // Set TRUE on every sample for uncompressed frames
+ pSample->SetSyncPoint(TRUE);
+ }
+
+ this->m_progress += this->m_outputFps;
+ this->m_iFrameNumber++;
+
+ return ret;
+}
+
+HRESULT DSFrameRateFilter::CheckInputType(const CMediaType* mtIn)
+{
+ return S_OK;
+}
+
+//Implement CreateInstance for your filter object. Typically, CreateInstance calls the constructor of your filter clas
+CUnknown * WINAPI DSFrameRateFilter::CreateInstance(LPUNKNOWN punk, HRESULT *phr)
+{
+ DSFrameRateFilter *pNewObject = new DSFrameRateFilter(_T("Tdshow DirectShow Framerate Limiter Filter."), punk, phr );
+ if (pNewObject == NULL) {
+ *phr = E_OUTOFMEMORY;
+ }
+ return pNewObject;
+}
diff --git a/plugins/pluginDirectShow/internals/DSFrameRateFilter.h b/plugins/pluginDirectShow/internals/DSFrameRateFilter.h
new file mode 100644
index 0000000..9f2296e
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/DSFrameRateFilter.h
@@ -0,0 +1,64 @@
+/* Copyright (C) 2011-2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#ifndef PLUGIN_DSHOW_DSFRAMERATEFILTER_H
+#define PLUGIN_DSHOW_DSFRAMERATEFILTER_H
+
+#include "plugin_dshow_config.h"
+
+#include <streams.h>
+#include <math.h>
+
+class DSFrameRateFilter : public CTransInPlaceFilter
+{
+public:
+ DSFrameRateFilter(TCHAR *tszName, LPUNKNOWN punk, HRESULT *phr);
+ ~DSFrameRateFilter(void);
+
+public:
+ HRESULT Transform(IMediaSample *pSample);
+ HRESULT CheckInputType(const CMediaType* mtIn);
+
+public:
+ /**
+ * \def SetFps
+ * \brief fps1 define source .
+ */
+ HRESULT SetFps(int inputFps, int outputFps);
+
+ static CUnknown *WINAPI CreateInstance(LPUNKNOWN punk, HRESULT *phr);
+ DECLARE_IUNKNOWN;
+
+ /*STDMETHODIMP_(ULONG) NonDelegatingRelease()
+ {
+ if(InterlockedDecrement(&m_cRef) == 0)
+ {
+ delete this;
+ return 0;
+ }
+ return m_cRef;
+ }*/
+
+private:
+ int m_progress;
+ int m_inputFps, m_outputFps;
+ bool m_bProcessFrame;
+ REFERENCE_TIME m_rtFrameLength; // UNITS/fps
+ LONGLONG m_iFrameNumber;
+};
+
+#endif ////DSFrameRateFilter_H \ No newline at end of file
diff --git a/plugins/pluginDirectShow/internals/DSGrabber.cxx b/plugins/pluginDirectShow/internals/DSGrabber.cxx
new file mode 100644
index 0000000..e4dc3a7
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/DSGrabber.cxx
@@ -0,0 +1,292 @@
+/* Copyright (C) 2011-2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#include "internals/DSGrabber.h"
+#include "internals/DSDisplay.h"
+#include "internals/DSUtils.h"
+#include "internals/DSCaptureUtils.h"
+#include "internals/Resizer.h"
+#include "internals/DSUtils.h"
+#include "internals/DSCaptureGraph.h"
+#if !defined(_WIN32_WCE)
+# include "internals/DSScreenCastGraph.h"
+#endif
+
+#include "tsk_debug.h"
+
+#include <assert.h>
+
+using namespace std;
+
+DSGrabber::DSGrabber(HRESULT *hr, BOOL _screenCast)
+: mutex_buffer(NULL), preview(NULL)
+, screenCast(_screenCast)
+{
+#if defined(_WIN32_WCE)
+ assert(!screenCast);
+ this->graph = new DSCaptureGraph(this, hr);
+ CHECK_HR((*hr));
+#else
+ this->graph = screenCast ? dynamic_cast<DSBaseCaptureGraph*>(new DSScreenCastGraph(this, hr)) : dynamic_cast<DSBaseCaptureGraph*>(new DSCaptureGraph(this, hr));
+ CHECK_HR((*hr));
+ this->preview = new DSDisplay(hr);
+#endif
+
+ // Init the bitmap info header with default values
+ memset(&(this->bitmapInfo), 0, sizeof(BITMAPINFOHEADER));
+ this->bitmapInfo.biSize = sizeof(BITMAPINFOHEADER);
+ this->bitmapInfo.biWidth = 352;
+ this->bitmapInfo.biHeight = 288;
+ this->bitmapInfo.biPlanes = 1;
+ this->bitmapInfo.biBitCount = 24;
+ this->bitmapInfo.biCompression = 0;
+ this->bitmapInfo.biXPelsPerMeter = 0;
+ this->bitmapInfo.biYPelsPerMeter = 0;
+ this->bitmapInfo.biClrUsed = 0;
+ this->bitmapInfo.biClrImportant = 0;
+
+ this->plugin_cb = NULL;
+ this->buffer = NULL;
+ this->mutex_buffer = tsk_mutex_create();
+
+bail: ;
+}
+
+DSGrabber::~DSGrabber()
+{
+ SAFE_DELETE_PTR ( this->graph );
+ SAFE_DELETE_PTR ( this->preview );
+ SAFE_DELETE_ARRAY ( this->buffer );
+ tsk_mutex_destroy(&this->mutex_buffer);
+}
+
+void DSGrabber::setCaptureDevice(const std::string &devicePath)
+{
+ this->graph->setSource(devicePath);
+}
+
+void DSGrabber::setCallback(tmedia_producer_enc_cb_f callback, const void* callback_data)
+{
+ this->plugin_cb = callback;
+ this->plugin_cb_data = callback_data;
+}
+
+void DSGrabber::start()
+{
+ if(this->graph->isPaused()){
+ this->graph->start();
+ this->preview->start();
+ return;
+ }
+
+ if (!this->graph->isRunning()){
+ first_buffer = true;
+
+ if(this->preview){
+ this->preview->start();
+ }
+ this->graph->connect();
+ this->graph->start();
+ }
+}
+
+void DSGrabber::pause()
+{
+ if(this->graph && this->graph->isRunning()){
+ this->graph->pause();
+ this->preview->pause();
+ }
+}
+
+void DSGrabber::stop()
+{
+ if (this->graph->isRunning()){
+ if(this->preview){
+ this->preview->stop();
+ }
+ this->graph->stop();
+ this->graph->disconnect();
+ }
+}
+
+bool DSGrabber::setCaptureParameters(int w, int h, int f)
+{
+ tsk_mutex_lock(this->mutex_buffer);
+
+ // Store the framerate
+ this->fps = f;
+ this->width = w;
+ this->height = h;
+
+ // Store the required dimensions
+ this->bitmapInfo.biWidth = this->width;
+ this->bitmapInfo.biHeight = this->height;
+ this->bitmapInfo.biBitCount = 24;
+ this->bitmapInfo.biSizeImage = (this->width * this->height * 3);
+
+ // Change the intermediate buffer
+ SAFE_DELETE_ARRAY ( this->buffer );
+ this->buffer = new BYTE[this->bitmapInfo.biSizeImage];
+ memset(this->buffer,0,this->bitmapInfo.biSizeImage);
+
+ // Find closest matching format to drive the source filter
+ DSCaptureFormat *fmt = NULL;
+ int score = 0;
+ std::vector<DSCaptureFormat> *formats = this->graph->getFormats();
+ std::vector<DSCaptureFormat>::iterator iter;
+ std::vector<DSCaptureFormat>::iterator last = formats->end();
+ for(iter = formats->begin(); iter != last; iter++){
+ int value = (*iter).getMatchScore(this->width, this->height);
+ if (value > score || !fmt){
+ score = value;
+ fmt = &(*iter);
+ }
+ }
+
+ // Setup source filter in the graph
+ HRESULT hr = this->graph->setParameters(fmt, this->fps);
+ // Set preview parameters
+ if(this->preview){
+ this->preview->setFps(this->fps);
+ this->preview->setSize(this->width, this->height);
+ }
+
+ tsk_mutex_unlock(this->mutex_buffer);
+
+ return SUCCEEDED(hr);
+}
+
+void DSGrabber::setPluginFirefox(bool value)
+{
+ if(this->preview){
+ this->preview->setPluginFirefox(value);
+ }
+}
+
+bool DSGrabber::setCaptureParameters(int format, int f)
+{
+ int w, h;
+ // Get size from the format
+ VIDEOFORMAT_TO_SIZE(format, w, h);
+ return this->setCaptureParameters(w, h, f);
+}
+
+int DSGrabber::getFramerate()
+{
+ return this->fps;
+}
+
+HRESULT DSGrabber::getConnectedMediaType(AM_MEDIA_TYPE *mediaType)
+{
+ if (!this->graph || !mediaType) {
+ return E_INVALIDARG;
+ }
+ return this->graph->getConnectedMediaType(mediaType);
+}
+
+HRESULT DSGrabber::SampleCB(double SampleTime, IMediaSample *pSample)
+{
+ return S_OK;
+}
+
+HRESULT DSGrabber::BufferCB(double SampleTime, BYTE *pBuffer, long BufferLen)
+{
+ HRESULT hr;
+
+ tsk_mutex_lock(this->mutex_buffer);
+
+ AM_MEDIA_TYPE mediaType;
+ hr = this->graph->getConnectedMediaType(&mediaType);
+ if (FAILED(hr) || !this->buffer){
+ return hr;
+ }
+
+ if(first_buffer){
+ first_buffer = false;
+
+ tsk_mutex_unlock(this->mutex_buffer);
+ return hr;
+ }
+
+ // Examine the format block.
+ if ((mediaType.formattype == FORMAT_VideoInfo) && (mediaType.cbFormat >= sizeof(VIDEOINFOHEADER)) && (mediaType.pbFormat != NULL) )
+ {
+ VIDEOINFOHEADER *pVih = reinterpret_cast<VIDEOINFOHEADER *>(mediaType.pbFormat);
+ BITMAPINFOHEADER* bih = &pVih->bmiHeader;
+
+ //int framerate = pVih->AvgTimePerFrame;
+ if( (bih->biHeight == this->bitmapInfo.biHeight) && (bih->biWidth == this->bitmapInfo.biWidth) && (bih->biBitCount == this->bitmapInfo.biBitCount) )
+ {
+ memmove(this->buffer, pBuffer, this->bitmapInfo.biSizeImage);
+ }
+ else
+ {
+ ResizeRGB(
+ bih,
+ (const unsigned char *) pBuffer,
+ &this->bitmapInfo,
+ (unsigned char *) this->buffer,
+ this->width,
+ this->height);
+ }
+
+ // for the network
+ if(this->plugin_cb){
+ this->plugin_cb(this->plugin_cb_data, this->buffer, (this->width*this->height*3));
+ }
+
+ // for the preview
+ if(this->preview){
+ this->preview->handleVideoFrame(this->buffer, this->width, this->height);
+ }
+ }
+
+ // Free the format
+#ifdef _WIN32_WCE
+ // Nothing had been allocated
+#else
+ FreeMediaType(mediaType);
+#endif
+
+ tsk_mutex_unlock(this->mutex_buffer);
+
+ return hr;
+}
+
+HRESULT DSGrabber::QueryInterface(REFIID iid, LPVOID *ppv)
+{
+#ifdef _WIN32_WCE
+ assert(1==0);
+#else
+ if( iid == IID_ISampleGrabberCB || iid == IID_IUnknown )
+ {
+ *ppv = (void *) static_cast<ISampleGrabberCB*>(this);
+ return NOERROR;
+ }
+#endif
+ return E_NOINTERFACE;
+}
+
+ULONG DSGrabber::AddRef()
+{
+ return 2;
+}
+
+ULONG DSGrabber::Release()
+{
+ return 1;
+} \ No newline at end of file
diff --git a/plugins/pluginDirectShow/internals/DSGrabber.h b/plugins/pluginDirectShow/internals/DSGrabber.h
new file mode 100644
index 0000000..64cde75
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/DSGrabber.h
@@ -0,0 +1,92 @@
+/* Copyright (C) 2011-2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#ifndef PLUGIN_DSHOW_DIRECTSHOW_GRABBER_H
+#define PLUGIN_DSHOW_DIRECTSHOW_GRABBER_H
+
+#include "plugin_dshow_config.h"
+
+#include "internals/DSBaseCaptureGraph.h"
+#include "internals/VideoFrame.h"
+
+#include "tinymedia/tmedia_producer.h"
+
+#include "tsk_mutex.h"
+
+class DSDisplay;
+
+#if defined(_WIN32_WCE)
+# include "internals/wince/DSISampleGrabberCB.h"
+#endif
+
+
+class DSGrabber : public
+#if defined(_WIN32_WCE)
+ DSISampleGrabberCB
+#else
+ ISampleGrabberCB
+#endif
+{
+public:
+ DSGrabber(HRESULT *hr, BOOL screenCast);
+ virtual ~DSGrabber();
+
+ void setCallback(tmedia_producer_enc_cb_f callback, const void* callback_data);
+ void setCaptureDevice(const std::string &devicePath);
+
+ virtual void start();
+ virtual void pause();
+ virtual void stop();
+
+ virtual bool setCaptureParameters(int format, int f);
+ virtual bool setCaptureParameters(int w, int h, int f);
+
+ virtual void setPluginFirefox(bool value);
+
+ virtual int getFramerate();
+ virtual HRESULT getConnectedMediaType(AM_MEDIA_TYPE *mediaType);
+
+ virtual HRESULT STDMETHODCALLTYPE SampleCB(double SampleTime, IMediaSample *pSample);
+ virtual HRESULT STDMETHODCALLTYPE BufferCB(double SampleTime, BYTE *pBuffer, long BufferLen);
+
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject);
+ virtual ULONG STDMETHODCALLTYPE AddRef();
+ virtual ULONG STDMETHODCALLTYPE Release();
+
+ DSDisplay *preview;
+
+private:
+ int width;
+ int height;
+ int fps;
+
+ DSBaseCaptureGraph *graph;
+
+ //VideoFrame *currentFrame;
+ BITMAPINFOHEADER bitmapInfo;
+ BYTE *buffer;
+
+ tsk_mutex_handle_t *mutex_buffer;
+
+ BOOL first_buffer;
+ BOOL screenCast;
+
+ const void* plugin_cb_data;
+ tmedia_producer_enc_cb_f plugin_cb;
+};
+
+#endif
diff --git a/plugins/pluginDirectShow/internals/DSOutputFilter.cxx b/plugins/pluginDirectShow/internals/DSOutputFilter.cxx
new file mode 100644
index 0000000..ab5aa0f
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/DSOutputFilter.cxx
@@ -0,0 +1,113 @@
+/*
+* Copyright (C) 2010-2011 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+#include "internals/DSOutputFilter.h"
+#include "internals/DSOutputStream.h"
+#include "internals/DSUtils.h"
+
+#include "tsk_memory.h"
+
+DSOutputFilter::DSOutputFilter(LPUNKNOWN pUnk, HRESULT *phr)
+: CSource(_T("TDSHOW_OUTPUT"), pUnk, CLSID_TdshowOutputFilter)
+{
+#if !(defined(_WIN32_WCE) && defined(_DEBUG))
+ CAutoLock cAutoLock(&m_cStateLock);
+#endif
+
+ // Add one source stream (output pin)!
+ this->outputStream = new DSOutputStream(phr, this, _T("Out"));
+}
+
+DSOutputFilter::~DSOutputFilter()
+{
+ //SAFE_RELEASE(this->outputStream);
+}
+
+void DSOutputFilter::setBuffer(void *pointer, int size)
+{
+ this->outputStream->lockBuffer();
+ if(pointer && size){
+ if(this->outputStream->buffer_size != size){
+ if((this->outputStream->buffer = tsk_realloc(this->outputStream->buffer, size))){
+ this->outputStream->buffer_size = size;
+ }
+ else goto done;
+ }
+ memcpy(this->outputStream->buffer, pointer, size);
+ }
+done:
+ this->outputStream->unlockBuffer();
+}
+
+void DSOutputFilter::getMediaType(AM_MEDIA_TYPE* &pmt)
+{
+ //if(pmt)
+ //{
+ // memcpy(pmt, &this->outputStream->pmt, sizeof(AM_MEDIA_TYPE));
+ //}
+}
+
+HRESULT DSOutputFilter::setMediaType(const AM_MEDIA_TYPE* pmt)
+{
+ return this->ReconnectPin(this->outputStream, pmt);
+}
+
+HRESULT DSOutputFilter::setImageFormat(UINT width, UINT height)
+{
+ return this->outputStream->setImageFormat(width, height);
+}
+
+bool DSOutputFilter::getImageFormat(UINT &width, UINT &height)
+{
+ if(this->outputStream){
+ return this->outputStream->getImageFormat(width, height);
+ }
+ return false;
+}
+
+void DSOutputFilter::setFps(int fps_)
+{
+ this->outputStream->setFps(fps_);
+}
+
+void DSOutputFilter::showOverlay(int value)
+{
+ this->outputStream->showOverlay(value);
+}
+
+void DSOutputFilter::reset()
+{
+ this->outputStream->frameNumber = 0;
+ this->outputStream->lockBuffer();
+ this->outputStream->buffer = NULL;
+ this->outputStream->buffer_size = 0;
+ this->outputStream->unlockBuffer();
+}
+
+#ifdef _WIN32_WCE
+STDMETHODIMP_(ULONG) DSOutputFilter::NonDelegatingRelease()
+{
+ if(InterlockedDecrement(&m_cRef) == 0)
+ {
+ delete this;
+ return 0;
+ }
+ return m_cRef;
+}
+#endif
diff --git a/plugins/pluginDirectShow/internals/DSOutputFilter.h b/plugins/pluginDirectShow/internals/DSOutputFilter.h
new file mode 100644
index 0000000..fea2d23
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/DSOutputFilter.h
@@ -0,0 +1,112 @@
+/* Copyright (C) 2011-2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#ifndef PLUGIN_DSHOW_DSOUTPUTFILTER_H
+#define PLUGIN_DSHOW_DSOUTPUTFILTER_H
+
+#include "plugin_dshow_config.h"
+
+#include "internals/DSBufferWriter.h"
+#include <streams.h>
+
+class DSOutputStream;
+
+// {17D9D5CB-850D-4339-B72A-F72D084D8D64}
+TDSHOW_DEFINE_GUID(CLSID_TdshowOutputFilter,
+0x17d9d5cb, 0x850d, 0x4339, 0xb7, 0x2a, 0xf7, 0x2d, 0x8, 0x4d, 0x8d, 0x64);
+
+class DSOutputFilter : public CSource, public DSBufferWriter
+{
+public:
+ DSOutputFilter(LPUNKNOWN pUnk, HRESULT *phr);
+ virtual ~DSOutputFilter();
+
+ //static CUnknown * WINAPI CreateInstance(LPUNKNOWN pUnk, HRESULT *phr);
+ DECLARE_IUNKNOWN;
+
+ virtual void setBuffer(void *pointer, int size);
+ virtual inline HRESULT setImageFormat(UINT width, UINT height);
+ virtual bool getImageFormat(UINT &width, UINT &height);
+
+ virtual void setFps(int fps_);
+ virtual void showOverlay(int value);
+
+ virtual void getMediaType(AM_MEDIA_TYPE* &pmt);
+ virtual HRESULT setMediaType(const AM_MEDIA_TYPE* pmt);
+
+ void reset();
+
+#ifdef _WIN32_WCE
+ STDMETHODIMP_(ULONG) NonDelegatingRelease();
+#endif
+
+//protected:
+#ifdef _WIN32_WCE
+ /*STDMETHODIMP QueryInterface(REFIID riid, void **ppv)
+ {
+ CheckPointer(ppv, E_POINTER);
+
+ if (riid == IID_IBaseFilter
+ || riid == IID_IBaseFilter
+ || riid == IID_IUnknown
+ || riid == IID_IMediaFilter
+ )
+ {
+ return GetInterface((IBaseFilter *) this, ppv);
+ }
+ else
+ {
+ *ppv = NULL;
+ return E_NOINTERFACE;
+ }
+ };
+
+ STDMETHODIMP_(ULONG) AddRef() {
+ //return GetOwner()->AddRef();
+ //return 1;
+ return (ULONG)InterlockedIncrement(&m_cRef);
+ };
+
+ STDMETHODIMP_(ULONG) Release() {
+ LONG lRefCount = InterlockedDecrement(&m_cRef);
+ if(m_cRef < 1) delete this;
+ return (ULONG)m_cRef;
+ };
+
+ STDMETHODIMP_(ULONG) NonDelegatingAddRef()
+ {
+ return InterlockedIncrement(&m_cRef);
+ }*/
+#endif
+/*
+ STDMETHODIMP_(ULONG) NonDelegatingRelease()
+ {
+ if(InterlockedDecrement(&m_cRef) == 0)
+ {
+ delete this;
+ return 0;
+ }
+ return m_cRef;
+ }*/
+
+private:
+ DSOutputStream *outputStream;
+
+ friend class DSOutputStream;
+};
+
+#endif
diff --git a/plugins/pluginDirectShow/internals/DSOutputStream.cxx b/plugins/pluginDirectShow/internals/DSOutputStream.cxx
new file mode 100644
index 0000000..670d0ae
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/DSOutputStream.cxx
@@ -0,0 +1,313 @@
+/* Copyright (C) 2011-2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#include "internals/DSOutputStream.h"
+#include "internals/DSOutputFilter.h"
+#include "internals/DSUtils.h"
+
+#include <iostream>
+
+#include "tsk_memory.h"
+
+using namespace std;
+
+#define DEFAULT_FPS 15
+
+#define MEMCPY_WORKAROUND 1
+
+// Overlay
+#define OVERLAY 0
+#define OVERLAY_TEXT TEXT("Press ESC to exit full screen mode")
+#define OVERLAY_DURATION 3 // in seconds
+
+DSOutputStream::DSOutputStream(HRESULT *phr, DSOutputFilter *pParent, LPCWSTR pPinName)
+: CSourceStream(_T("DSOutputStream"), phr, pParent, pPinName)
+{
+#if !(defined(_WIN32_WCE) && defined(_DEBUG))
+ CAutoLock cAutoLock(m_pFilter->pStateLock());
+#endif
+
+ this->buffer = NULL;
+ this->buffer_size = NULL;
+
+ this->frameNumber = 0;
+ this->frameLength = (1000)/DEFAULT_FPS;
+ this->fps = DEFAULT_FPS;
+
+ this->width = 352;
+ this->height = 288;
+
+ this->overlay = false;
+
+ this->paintBuffer = NULL;
+ this->paintDC = NULL;
+ this->hDibSection = NULL;
+ this->hObject = NULL;
+
+ this->mutex = tsk_mutex_create();
+}
+
+DSOutputStream::~DSOutputStream()
+{
+ TSK_FREE(this->buffer);
+ tsk_mutex_destroy(&this->mutex);
+ // TODO : Is there anything to free ???
+}
+
+void DSOutputStream::setFps(int fps_)
+{
+ this->fps = fps_;
+ this->frameLength = (1000)/this->fps;
+}
+
+void DSOutputStream::showOverlay(int value)
+{
+ if (value == 0){
+ this->overlay = false;
+ }
+ this->overlay = (value > 0);
+}
+
+HRESULT DSOutputStream::setImageFormat(UINT width, UINT height)
+{
+ if ((this->width == width) && (this->height == height)) return S_FALSE;
+
+ this->width = width;
+ this->height = height;
+
+ this->frameNumber = 0;
+
+ return S_OK;
+}
+
+bool DSOutputStream::getImageFormat(UINT &width, UINT &height)
+{
+ width = this->width;
+ height = this->height;
+ return true;
+}
+
+HRESULT DSOutputStream::GetMediaType(CMediaType *pMediaType)
+{
+ HRESULT hr = S_OK;
+#if !(defined(_WIN32_WCE) && defined(_DEBUG))
+ CAutoLock lock(m_pFilter->pStateLock());
+#endif
+
+ ZeroMemory(pMediaType, sizeof(CMediaType));
+
+ VIDEOINFO *pvi = (VIDEOINFO *)pMediaType->AllocFormatBuffer(sizeof(VIDEOINFO));
+ if (NULL == pvi)
+ return E_OUTOFMEMORY;
+
+ ZeroMemory(pvi, sizeof(VIDEOINFO));
+
+ pvi->bmiHeader.biCompression = BI_RGB;
+ pvi->bmiHeader.biBitCount = 24;
+ pvi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ pvi->bmiHeader.biWidth = this->width;
+ pvi->bmiHeader.biHeight = this->height;
+ pvi->bmiHeader.biPlanes = 1;
+ pvi->bmiHeader.biSizeImage = GetBitmapSize(&pvi->bmiHeader);
+ pvi->bmiHeader.biClrImportant = 0;
+
+ // Frame rate
+ pvi->AvgTimePerFrame = DS_MILLIS_TO_100NS(1000/this->fps);
+
+ SetRectEmpty(&(pvi->rcSource)); // we want the whole image area rendered.
+ SetRectEmpty(&(pvi->rcTarget)); // no particular destination rectangle
+
+ pMediaType->SetType(&MEDIATYPE_Video);
+ pMediaType->SetFormatType(&FORMAT_VideoInfo);
+ pMediaType->SetTemporalCompression(FALSE);
+
+ pMediaType->SetSubtype(&MEDIASUBTYPE_RGB24);
+ pMediaType->SetSampleSize(pvi->bmiHeader.biSizeImage);
+
+ bitmapInfo.bmiHeader = pvi->bmiHeader;
+
+ return hr;
+}
+
+HRESULT DSOutputStream::DecideBufferSize(IMemAllocator *pMemAlloc, ALLOCATOR_PROPERTIES *pProperties)
+{
+ CheckPointer(pMemAlloc, E_POINTER);
+ CheckPointer(pProperties, E_POINTER);
+
+#if !(defined(_WIN32_WCE) && defined(_DEBUG))
+ CAutoLock cAutoLock(m_pFilter->pStateLock());
+#endif
+
+ HRESULT hr = NOERROR;
+
+ VIDEOINFO *pvi = (VIDEOINFO *) m_mt.Format();
+ pProperties->cBuffers = 1;
+ pProperties->cbBuffer = pvi->bmiHeader.biSizeImage;
+
+ // Ask the allocator to reserve us some sample memory. NOTE: the function
+ // can succeed (return NOERROR) but still not have allocated the
+ // memory that we requested, so we must check we got whatever we wanted.
+ ALLOCATOR_PROPERTIES Actual;
+ hr = pMemAlloc->SetProperties(pProperties,&Actual);
+ if(FAILED(hr)){
+ return hr;
+ }
+
+ // Is this allocator unsuitable?
+ if(Actual.cbBuffer < pProperties->cbBuffer)
+ {
+ return E_FAIL;
+ }
+
+ // Make sure that we have only 1 buffer (we erase the ball in the
+ // old buffer to save having to zero a 200k+ buffer every time
+ // we draw a frame)
+ return NOERROR;
+}
+
+HRESULT DSOutputStream::OnThreadCreate()
+{
+#if OVERLAY
+ hDibSection = CreateDIBSection(NULL, (BITMAPINFO *) &bitmapInfo, DIB_RGB_COLORS, &paintBuffer, NULL, 0);
+
+ HDC hDC = GetDC(NULL);
+ paintDC = CreateCompatibleDC(hDC);
+ SetMapMode(paintDC, GetMapMode(hDC));
+ SetBkMode(paintDC, TRANSPARENT);
+ SetTextColor(paintDC, RGB(255,255,255));
+
+ hObject = SelectObject(paintDC, hDibSection);
+#endif
+
+ return CSourceStream::OnThreadCreate();
+}
+
+HRESULT DSOutputStream::OnThreadDestroy()
+{
+#if OVERLAY
+ if (paintDC) DeleteDC(paintDC);
+ if (hObject) DeleteObject(hObject);
+
+ if (paintBuffer)
+ {
+ //delete[] paintBuffer; // will be done
+ //paintBuffer = NULL;
+ }
+#endif
+ return CSourceStream::OnThreadDestroy();
+}
+
+inline HRESULT DSOutputStream::DrawOverLay(void *pBuffer, long lSize)
+{
+ // called only #if OVERLAY
+ CopyMemory(paintBuffer, pBuffer, lSize);
+
+ // Draw the current frame
+#ifdef _WIN32_WCE
+
+#else
+ if( !TextOut( paintDC, 0, 0, OVERLAY_TEXT, (int)_tcslen( OVERLAY_TEXT ) ) ) return E_FAIL;
+#endif
+
+ CopyMemory(pBuffer, paintBuffer, lSize);
+
+ return S_OK;
+}
+
+static __inline void TransfertBuffer(void* src, void* dest, long lSize)
+{
+ __try
+ {
+#if MEMCPY_WORKAROUND
+ //#ifdef _WIN32_WCE
+ memmove(dest, src, lSize);
+ /*#else
+ unsigned char * pDst = (unsigned char *) dest;
+
+ if(src){
+ unsigned char const * pSrc = (unsigned char const *) src;
+ for( register int i=0; ((i< lSize) && src); i++) *pDst++ = *pSrc++;
+ }else{
+ for( register int i=0; i< lSize; i++) *pDst++ = 0;
+ }
+ #endif*/
+#else
+ CopyMemory(dest, src, lSize); //BUGGY
+#endif
+ }
+ __except(EXCEPTION_ACCESS_VIOLATION == GetExceptionCode())
+ {
+ //ZeroMemory(dest, sizeof(void*));
+ }
+}
+
+HRESULT DSOutputStream::FillBuffer(IMediaSample *pSample)
+{
+ CheckPointer(pSample, E_POINTER);
+#if !(defined(_WIN32_WCE) && defined(_DEBUG))
+ CAutoLock lock(m_pFilter->pStateLock());
+#endif
+
+ HRESULT hr;
+ BYTE *pBuffer = NULL;
+ long lSize, lDataSize;
+
+ hr = pSample->GetPointer(&pBuffer);
+ if (SUCCEEDED(hr))
+ {
+ lDataSize = lSize = pSample->GetSize();
+
+ // Check that we're still using video
+ //ASSERT(m_mt.formattype == FORMAT_VideoInfo);
+
+ if (this->buffer)
+ {
+#if OVERLAY
+ if (this->overlay)
+ {
+ DrawOverLay(this->buffer, lSize);
+ }
+#endif
+ // Why try do not work, see: http://msdn2.microsoft.com/en-us/library/xwtb73ad(vs.80).aspx
+ this->lockBuffer();
+ lDataSize = TSK_MIN(lSize, this->buffer_size);
+ TransfertBuffer(this->buffer, (void*)pBuffer, lDataSize);
+ this->unlockBuffer();
+ }
+ else
+ {
+ // Avoid caching last image
+ memset((void*)pBuffer, NULL, lSize);
+ }
+
+ REFERENCE_TIME rtStart = DS_MILLIS_TO_100NS(this->frameNumber * this->frameLength);
+ REFERENCE_TIME rtStop = rtStart + DS_MILLIS_TO_100NS(this->frameLength);
+
+ this->frameNumber++;
+
+ pSample->SetTime(&rtStart, &rtStop);
+ //pSample->SetMediaTime(&rtStart, &rtStop);
+ pSample->SetActualDataLength(lDataSize);
+ pSample->SetPreroll(FALSE);
+ pSample->SetDiscontinuity(FALSE);
+ }
+
+ // Set TRUE on every sample for uncompressed frames (KEYFRAME)
+ pSample->SetSyncPoint(TRUE);
+
+ return S_OK;
+}
diff --git a/plugins/pluginDirectShow/internals/DSOutputStream.h b/plugins/pluginDirectShow/internals/DSOutputStream.h
new file mode 100644
index 0000000..db3ede4
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/DSOutputStream.h
@@ -0,0 +1,90 @@
+/* Copyright (C) 2011-2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#ifndef PLUGIN_DSHOW_DSOUTPUTSTREAM_H
+#define PLUGIN_DSHOW_DSOUTPUTSTREAM_H
+
+#include "plugin_dshow_config.h"
+
+#include <streams.h>
+
+#include "tsk_mutex.h"
+
+class DSOutputFilter;
+
+class DSOutputStream : public CSourceStream
+{
+public:
+ DSOutputStream(HRESULT *phr, DSOutputFilter *pParent, LPCWSTR pPinName);
+ virtual ~DSOutputStream();
+
+ void setFps(int fps_);
+ void showOverlay(int value);
+
+ HRESULT setImageFormat(UINT width, UINT height);
+ bool getImageFormat(UINT &width, UINT &height);
+ STDMETHODIMP Notify(IBaseFilter *pSelf, Quality q) { return E_NOTIMPL; };
+ inline bool lockBuffer() {
+ if (this->mutex) {
+ return tsk_mutex_lock(this->mutex) == 0;
+ }
+ return false;
+ }
+ inline bool unlockBuffer() {
+ if (this->mutex) {
+ return tsk_mutex_unlock(this->mutex) == 0;
+ }
+ return false;
+ }
+
+public:
+ void *buffer;
+ int buffer_size;
+ LONGLONG frameNumber;
+
+protected: // Overrides
+ HRESULT GetMediaType(CMediaType *pMediaType);
+ HRESULT DecideBufferSize(IMemAllocator *pMemAlloc, ALLOCATOR_PROPERTIES *pProperties);
+ HRESULT OnThreadCreate();
+ HRESULT OnThreadDestroy();
+ HRESULT FillBuffer(IMediaSample *pSample);
+
+private:
+ inline HRESULT DrawOverLay(void *pBuffer, long lSize);
+
+private:
+ // TIMING
+ REFERENCE_TIME frameLength;
+ int fps;
+
+ // sizing
+ UINT width;
+ UINT height;
+
+ // overlaying
+ bool overlay;
+ BITMAPINFO bitmapInfo;
+ void *paintBuffer;
+ HDC paintDC;
+ HBITMAP hDibSection;
+ HGDIOBJ hObject;
+
+ tsk_mutex_handle_t* mutex;
+};
+
+
+#endif
diff --git a/plugins/pluginDirectShow/internals/DSPushSource.h b/plugins/pluginDirectShow/internals/DSPushSource.h
new file mode 100644
index 0000000..140d9bd
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/DSPushSource.h
@@ -0,0 +1,496 @@
+//------------------------------------------------------------------------------
+// File: PushSource.H
+//
+// Desc: DirectShow sample code - In-memory push mode source filter
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------------------------
+#ifndef PLUGIN_DSHOW_DSPUSHSOURCE_H
+#define PLUGIN_DSHOW_DSPUSHSOURCE_H
+
+#include "plugin_dshow_config.h"
+
+#include <strsafe.h>
+
+// UNITS = 10 ^ 7
+// UNITS / 30 = 30 fps;
+// UNITS / 20 = 20 fps, etc
+const REFERENCE_TIME FPS_30 = UNITS / 30;
+const REFERENCE_TIME FPS_20 = UNITS / 20;
+const REFERENCE_TIME FPS_10 = UNITS / 10;
+const REFERENCE_TIME FPS_5 = UNITS / 5;
+const REFERENCE_TIME FPS_4 = UNITS / 4;
+const REFERENCE_TIME FPS_3 = UNITS / 3;
+const REFERENCE_TIME FPS_2 = UNITS / 2;
+const REFERENCE_TIME FPS_1 = UNITS / 1;
+
+const REFERENCE_TIME rtDefaultFrameLength = FPS_10;
+
+// Filter name strings
+#define g_wszPushBitmap L"PushSource Bitmap Filter"
+#define g_wszPushBitmapSet L"PushSource BitmapSet Filter"
+#define g_wszPushDesktop L"PushSource Desktop Filter"
+
+// Number of bitmap files to load in the CPushPinBitmapSet class
+#define NUM_FILES 5
+
+// {3FD3081A-A8C9-4958-9F75-07EC89690024}
+TDSHOW_DEFINE_GUID(CLSID_PushSourceDesktop,
+0x3fd3081a, 0xa8c9, 0x4958, 0x9f, 0x75, 0x7, 0xec, 0x89, 0x69, 0x0, 0x24);
+
+
+
+/**********************************************
+ *
+ * Class declarations
+ *
+ **********************************************/
+
+class CPushPinBitmap : public CSourceStream
+{
+protected:
+
+ int m_FramesWritten; // To track where we are in the file
+ BOOL m_bZeroMemory; // Do we need to clear the buffer?
+ CRefTime m_rtSampleTime; // The time stamp for each sample
+
+ BITMAPINFO *m_pBmi; // Pointer to the bitmap header
+ DWORD m_cbBitmapInfo; // Size of the bitmap header
+
+ // File opening variables
+ HANDLE m_hFile; // Handle returned from CreateFile
+ BYTE * m_pFile; // Points to beginning of file buffer
+ BYTE * m_pImage; // Points to pixel bits
+
+ int m_iFrameNumber;
+ const REFERENCE_TIME m_rtFrameLength;
+
+ CCritSec m_cSharedState; // Protects our internal state
+ CImageDisplay m_Display; // Figures out our media type for us
+
+public:
+
+ CPushPinBitmap(HRESULT *phr, CSource *pFilter);
+ ~CPushPinBitmap();
+
+ // Override the version that offers exactly one media type
+ HRESULT GetMediaType(CMediaType *pMediaType);
+ HRESULT DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pRequest);
+ HRESULT FillBuffer(IMediaSample *pSample);
+
+ // Quality control
+ // Not implemented because we aren't going in real time.
+ // If the file-writing filter slows the graph down, we just do nothing, which means
+ // wait until we're unblocked. No frames are ever dropped.
+ STDMETHODIMP Notify(IBaseFilter *pSelf, Quality q)
+ {
+ return E_FAIL;
+ }
+
+};
+
+
+class CPushPinBitmapSet : public CSourceStream
+{
+protected:
+
+ int m_FramesWritten; // To track where we are in the file
+ BOOL m_bZeroMemory; // Do we need to clear the buffer?
+ CRefTime m_rtSampleTime; // The time stamp for each sample
+
+ BITMAPINFO *m_pBmi[NUM_FILES]; // Pointer to the bitmap headers
+ DWORD m_cbBitmapInfo[NUM_FILES]; // Size of the bitmap headers
+
+ // File opening variables
+ HANDLE m_hFile[NUM_FILES]; // Handles returned from CreateFile
+ BYTE * m_pFile[NUM_FILES]; // Points to beginning of file buffers
+ BYTE * m_pImage[NUM_FILES]; // Points to pixel bits
+ BOOL m_bFilesLoaded;
+
+ int m_iCurrentBitmap; // Which bitmap is being displayed
+ int m_iFrameNumber; // How many frames have been displayed
+ const REFERENCE_TIME m_rtFrameLength; // Duration of one frame
+
+ CCritSec m_cSharedState; // Protects our internal state
+ CImageDisplay m_Display; // Figures out our media type for us
+
+public:
+
+ CPushPinBitmapSet(HRESULT *phr, CSource *pFilter);
+ ~CPushPinBitmapSet();
+
+ // Override the version that offers exactly one media type
+ HRESULT GetMediaType(CMediaType *pMediaType);
+ HRESULT DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pRequest);
+ HRESULT FillBuffer(IMediaSample *pSample);
+
+ // Quality control
+ // Not implemented because we aren't going in real time.
+ // If the file-writing filter slows the graph down, we just do nothing, which means
+ // wait until we're unblocked. No frames are ever dropped.
+ STDMETHODIMP Notify(IBaseFilter *pSelf, Quality q)
+ {
+ return E_FAIL;
+ }
+
+};
+
+
+class CPushPinDesktop : public CSourceStream
+{
+protected:
+
+ int m_FramesWritten; // To track where we are in the file
+ BOOL m_bZeroMemory; // Do we need to clear the buffer?
+ CRefTime m_rtSampleTime; // The time stamp for each sample
+
+ int m_iFrameNumber;
+ const REFERENCE_TIME m_rtFrameLength;
+
+ RECT m_rScreen; // Rect containing entire screen coordinates
+
+ int m_iImageHeight; // The current image height
+ int m_iImageWidth; // And current image width
+ int m_iRepeatTime; // Time in msec between frames
+ int m_nCurrentBitDepth; // Screen bit depth
+
+ CMediaType m_MediaType;
+ CCritSec m_cSharedState; // Protects our internal state
+ CImageDisplay m_Display; // Figures out our media type for us
+
+ HWND m_hSrcHwnd; // Handle to the window to grab
+
+public:
+
+ CPushPinDesktop(HRESULT *phr, CSource *pFilter);
+ ~CPushPinDesktop();
+
+ // Override the version that offers exactly one media type
+ HRESULT DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pRequest);
+ HRESULT FillBuffer(IMediaSample *pSample);
+
+ // Set the agreed media type and set up the necessary parameters
+ HRESULT SetMediaType(const CMediaType *pMediaType);
+
+ // Support multiple display formats
+ HRESULT CheckMediaType(const CMediaType *pMediaType);
+ HRESULT GetMediaType(int iPosition, CMediaType *pmt);
+
+ // Quality control
+ // Not implemented because we aren't going in real time.
+ // If the file-writing filter slows the graph down, we just do nothing, which means
+ // wait until we're unblocked. No frames are ever dropped.
+ STDMETHODIMP Notify(IBaseFilter *pSelf, Quality q)
+ {
+ return E_FAIL;
+ }
+
+ HRESULT SetSrcHwnd(HWND hWnd)
+ {
+ m_hSrcHwnd = hWnd;
+ return S_OK;
+ }
+
+};
+
+
+
+class CPushSourceBitmap : public CSource
+{
+
+private:
+ // Constructor is private because you have to use CreateInstance
+ CPushSourceBitmap(IUnknown *pUnk, HRESULT *phr);
+ ~CPushSourceBitmap();
+
+ CPushPinBitmap *m_pPin;
+
+public:
+ static CUnknown * WINAPI CreateInstance(IUnknown *pUnk, HRESULT *phr);
+
+};
+
+
+class CPushSourceBitmapSet : public CSource
+{
+
+private:
+ // Constructor is private because you have to use CreateInstance
+ CPushSourceBitmapSet(IUnknown *pUnk, HRESULT *phr);
+ ~CPushSourceBitmapSet();
+
+ CPushPinBitmapSet *m_pPin;
+
+public:
+ static CUnknown * WINAPI CreateInstance(IUnknown *pUnk, HRESULT *phr);
+
+};
+
+
+class CPushSourceDesktop : public CSource
+{
+
+private:
+ // Constructor is private because you have to use CreateInstance
+ CPushSourceDesktop(IUnknown *pUnk, HRESULT *phr);
+ ~CPushSourceDesktop();
+
+ CPushPinDesktop *m_pPin;
+
+public:
+ static CUnknown * WINAPI CreateInstance(IUnknown *pUnk, HRESULT *phr);
+ DECLARE_IUNKNOWN;
+
+ HRESULT SetSrcHwnd(HWND hWnd);
+};
+
+
+#endif /* PLUGIN_DSHOW_DSPUSHSOURCE_H */
+//------------------------------------------------------------------------------
+// File: PushSource.H
+//
+// Desc: DirectShow sample code - In-memory push mode source filter
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------------------------
+#ifndef PLUGIN_DSHOW_DSPUSHSOURCE_H
+#define PLUGIN_DSHOW_DSPUSHSOURCE_H
+
+#include "plugin_dshow_config.h"
+
+#include <strsafe.h>
+
+// UNITS = 10 ^ 7
+// UNITS / 30 = 30 fps;
+// UNITS / 20 = 20 fps, etc
+const REFERENCE_TIME FPS_30 = UNITS / 30;
+const REFERENCE_TIME FPS_20 = UNITS / 20;
+const REFERENCE_TIME FPS_10 = UNITS / 10;
+const REFERENCE_TIME FPS_5 = UNITS / 5;
+const REFERENCE_TIME FPS_4 = UNITS / 4;
+const REFERENCE_TIME FPS_3 = UNITS / 3;
+const REFERENCE_TIME FPS_2 = UNITS / 2;
+const REFERENCE_TIME FPS_1 = UNITS / 1;
+
+const REFERENCE_TIME rtDefaultFrameLength = FPS_10;
+
+// Filter name strings
+#define g_wszPushBitmap L"PushSource Bitmap Filter"
+#define g_wszPushBitmapSet L"PushSource BitmapSet Filter"
+#define g_wszPushDesktop L"PushSource Desktop Filter"
+
+// Number of bitmap files to load in the CPushPinBitmapSet class
+#define NUM_FILES 5
+
+// {3FD3081A-A8C9-4958-9F75-07EC89690024}
+TDSHOW_DEFINE_GUID(CLSID_PushSourceDesktop,
+0x3fd3081a, 0xa8c9, 0x4958, 0x9f, 0x75, 0x7, 0xec, 0x89, 0x69, 0x0, 0x24);
+
+
+
+/**********************************************
+ *
+ * Class declarations
+ *
+ **********************************************/
+
+class CPushPinBitmap : public CSourceStream
+{
+protected:
+
+ int m_FramesWritten; // To track where we are in the file
+ BOOL m_bZeroMemory; // Do we need to clear the buffer?
+ CRefTime m_rtSampleTime; // The time stamp for each sample
+
+ BITMAPINFO *m_pBmi; // Pointer to the bitmap header
+ DWORD m_cbBitmapInfo; // Size of the bitmap header
+
+ // File opening variables
+ HANDLE m_hFile; // Handle returned from CreateFile
+ BYTE * m_pFile; // Points to beginning of file buffer
+ BYTE * m_pImage; // Points to pixel bits
+
+ int m_iFrameNumber;
+ const REFERENCE_TIME m_rtFrameLength;
+
+ CCritSec m_cSharedState; // Protects our internal state
+ CImageDisplay m_Display; // Figures out our media type for us
+
+public:
+
+ CPushPinBitmap(HRESULT *phr, CSource *pFilter);
+ ~CPushPinBitmap();
+
+ // Override the version that offers exactly one media type
+ HRESULT GetMediaType(CMediaType *pMediaType);
+ HRESULT DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pRequest);
+ HRESULT FillBuffer(IMediaSample *pSample);
+
+ // Quality control
+ // Not implemented because we aren't going in real time.
+ // If the file-writing filter slows the graph down, we just do nothing, which means
+ // wait until we're unblocked. No frames are ever dropped.
+ STDMETHODIMP Notify(IBaseFilter *pSelf, Quality q)
+ {
+ return E_FAIL;
+ }
+
+};
+
+
+class CPushPinBitmapSet : public CSourceStream
+{
+protected:
+
+ int m_FramesWritten; // To track where we are in the file
+ BOOL m_bZeroMemory; // Do we need to clear the buffer?
+ CRefTime m_rtSampleTime; // The time stamp for each sample
+
+ BITMAPINFO *m_pBmi[NUM_FILES]; // Pointer to the bitmap headers
+ DWORD m_cbBitmapInfo[NUM_FILES]; // Size of the bitmap headers
+
+ // File opening variables
+ HANDLE m_hFile[NUM_FILES]; // Handles returned from CreateFile
+ BYTE * m_pFile[NUM_FILES]; // Points to beginning of file buffers
+ BYTE * m_pImage[NUM_FILES]; // Points to pixel bits
+ BOOL m_bFilesLoaded;
+
+ int m_iCurrentBitmap; // Which bitmap is being displayed
+ int m_iFrameNumber; // How many frames have been displayed
+ const REFERENCE_TIME m_rtFrameLength; // Duration of one frame
+
+ CCritSec m_cSharedState; // Protects our internal state
+ CImageDisplay m_Display; // Figures out our media type for us
+
+public:
+
+ CPushPinBitmapSet(HRESULT *phr, CSource *pFilter);
+ ~CPushPinBitmapSet();
+
+ // Override the version that offers exactly one media type
+ HRESULT GetMediaType(CMediaType *pMediaType);
+ HRESULT DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pRequest);
+ HRESULT FillBuffer(IMediaSample *pSample);
+
+ // Quality control
+ // Not implemented because we aren't going in real time.
+ // If the file-writing filter slows the graph down, we just do nothing, which means
+ // wait until we're unblocked. No frames are ever dropped.
+ STDMETHODIMP Notify(IBaseFilter *pSelf, Quality q)
+ {
+ return E_FAIL;
+ }
+
+};
+
+
+class CPushPinDesktop : public CSourceStream
+{
+protected:
+
+ int m_FramesWritten; // To track where we are in the file
+ BOOL m_bZeroMemory; // Do we need to clear the buffer?
+ CRefTime m_rtSampleTime; // The time stamp for each sample
+
+ int m_iFrameNumber;
+ const REFERENCE_TIME m_rtFrameLength;
+
+ RECT m_rScreen; // Rect containing entire screen coordinates
+
+ int m_iImageHeight; // The current image height
+ int m_iImageWidth; // And current image width
+ int m_iRepeatTime; // Time in msec between frames
+ int m_nCurrentBitDepth; // Screen bit depth
+
+ CMediaType m_MediaType;
+ CCritSec m_cSharedState; // Protects our internal state
+ CImageDisplay m_Display; // Figures out our media type for us
+
+ HWND m_hSrcHwnd; // Handle to the window to grab
+
+public:
+
+ CPushPinDesktop(HRESULT *phr, CSource *pFilter);
+ ~CPushPinDesktop();
+
+ // Override the version that offers exactly one media type
+ HRESULT DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pRequest);
+ HRESULT FillBuffer(IMediaSample *pSample);
+
+ // Set the agreed media type and set up the necessary parameters
+ HRESULT SetMediaType(const CMediaType *pMediaType);
+
+ // Support multiple display formats
+ HRESULT CheckMediaType(const CMediaType *pMediaType);
+ HRESULT GetMediaType(int iPosition, CMediaType *pmt);
+
+ // Quality control
+ // Not implemented because we aren't going in real time.
+ // If the file-writing filter slows the graph down, we just do nothing, which means
+ // wait until we're unblocked. No frames are ever dropped.
+ STDMETHODIMP Notify(IBaseFilter *pSelf, Quality q)
+ {
+ return E_FAIL;
+ }
+
+ HRESULT SetSrcHwnd(HWND hWnd)
+ {
+ m_hSrcHwnd = hWnd;
+ return S_OK;
+ }
+
+};
+
+
+
+class CPushSourceBitmap : public CSource
+{
+
+private:
+ // Constructor is private because you have to use CreateInstance
+ CPushSourceBitmap(IUnknown *pUnk, HRESULT *phr);
+ ~CPushSourceBitmap();
+
+ CPushPinBitmap *m_pPin;
+
+public:
+ static CUnknown * WINAPI CreateInstance(IUnknown *pUnk, HRESULT *phr);
+
+};
+
+
+class CPushSourceBitmapSet : public CSource
+{
+
+private:
+ // Constructor is private because you have to use CreateInstance
+ CPushSourceBitmapSet(IUnknown *pUnk, HRESULT *phr);
+ ~CPushSourceBitmapSet();
+
+ CPushPinBitmapSet *m_pPin;
+
+public:
+ static CUnknown * WINAPI CreateInstance(IUnknown *pUnk, HRESULT *phr);
+
+};
+
+
+class CPushSourceDesktop : public CSource
+{
+
+private:
+ // Constructor is private because you have to use CreateInstance
+ CPushSourceDesktop(IUnknown *pUnk, HRESULT *phr);
+ ~CPushSourceDesktop();
+
+ CPushPinDesktop *m_pPin;
+
+public:
+ static CUnknown * WINAPI CreateInstance(IUnknown *pUnk, HRESULT *phr);
+ DECLARE_IUNKNOWN;
+
+ HRESULT SetSrcHwnd(HWND hWnd);
+};
+
+
+#endif /* PLUGIN_DSHOW_DSPUSHSOURCE_H */
diff --git a/plugins/pluginDirectShow/internals/DSPushSourceDesktop.cxx b/plugins/pluginDirectShow/internals/DSPushSourceDesktop.cxx
new file mode 100644
index 0000000..1bdee9e
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/DSPushSourceDesktop.cxx
@@ -0,0 +1,434 @@
+#if !defined(_WIN32_WCE)
+//------------------------------------------------------------------------------
+// File: PushSourceDesktop.cpp
+//
+// Desc: DirectShow sample code - In-memory push mode source filter
+// Provides an image of the user's desktop as a continuously updating stream.
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------------------------
+
+#include <streams.h>
+
+#include "DSPushSource.h"
+#include "DSDibHelper.h"
+#include "DSUtils.h"
+
+
+/**********************************************
+ *
+ * CPushPinDesktop Class
+ *
+ *
+ **********************************************/
+
+CPushPinDesktop::CPushPinDesktop(HRESULT *phr, CSource *pFilter)
+ : CSourceStream(NAME("Push Source Desktop"), phr, pFilter, L"Out"),
+ m_FramesWritten(0),
+ m_bZeroMemory(0),
+ m_iFrameNumber(0),
+ m_rtFrameLength(FPS_5), // Capture and display desktop 5 times per second
+ m_nCurrentBitDepth(24),
+ m_hSrcHwnd(NULL)
+{
+ // The main point of this sample is to demonstrate how to take a DIB
+ // in host memory and insert it into a video stream.
+
+ // To keep this sample as simple as possible, we just read the desktop image
+ // from a file and copy it into every frame that we send downstream.
+ //
+ // In the filter graph, we connect this filter to the AVI Mux, which creates
+ // the AVI file with the video frames we pass to it. In this case,
+ // the end result is a screen capture video (GDI images only, with no
+ // support for overlay surfaces).
+
+ // Get the device context of the main display
+ HDC hDC;
+ hDC = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
+
+ // Get the dimensions of the main desktop window
+ m_rScreen.left = m_rScreen.top = 0;
+ m_rScreen.right = GetDeviceCaps(hDC, HORZRES);
+ m_rScreen.bottom = GetDeviceCaps(hDC, VERTRES);
+
+ // Save dimensions for later use in FillBuffer()
+ m_iImageWidth = m_rScreen.right - m_rScreen.left;
+ m_iImageHeight = m_rScreen.bottom - m_rScreen.top;
+
+ // Release the device context
+ DeleteDC(hDC);
+}
+
+CPushPinDesktop::~CPushPinDesktop()
+{
+ DbgLog((LOG_TRACE, 3, TEXT("Frames written %d"), m_iFrameNumber));
+}
+
+
+//
+// GetMediaType
+//
+// Prefer 5 formats - 8, 16 (*2), 24 or 32 bits per pixel
+//
+// Prefered types should be ordered by quality, with zero as highest quality.
+// Therefore, iPosition =
+// 0 Return a 32bit mediatype
+// 1 Return a 24bit mediatype
+// 2 Return 16bit RGB565
+// 3 Return a 16bit mediatype (rgb555)
+// 4 Return 8 bit palettised format
+// >4 Invalid
+//
+HRESULT CPushPinDesktop::GetMediaType(int iPosition, CMediaType *pmt)
+{
+ CheckPointer(pmt,E_POINTER);
+ CAutoLock cAutoLock(m_pFilter->pStateLock());
+
+ if(iPosition < 0)
+ return E_INVALIDARG;
+
+ // Have we run off the end of types?
+ if(iPosition > 4)
+ return VFW_S_NO_MORE_ITEMS;
+
+ VIDEOINFO *pvi = (VIDEOINFO *) pmt->AllocFormatBuffer(sizeof(VIDEOINFO));
+ if(NULL == pvi)
+ return(E_OUTOFMEMORY);
+
+ // Initialize the VideoInfo structure before configuring its members
+ ZeroMemory(pvi, sizeof(VIDEOINFO));
+
+ switch(iPosition)
+ {
+ case 0:
+ {
+ // Return our highest quality 32bit format
+
+ // Since we use RGB888 (the default for 32 bit), there is
+ // no reason to use BI_BITFIELDS to specify the RGB
+ // masks. Also, not everything supports BI_BITFIELDS
+ pvi->bmiHeader.biCompression = BI_RGB;
+ pvi->bmiHeader.biBitCount = 32;
+ break;
+ }
+
+ case 1:
+ { // Return our 24bit format
+ pvi->bmiHeader.biCompression = BI_RGB;
+ pvi->bmiHeader.biBitCount = 24;
+ break;
+ }
+
+ case 2:
+ {
+ // 16 bit per pixel RGB565
+
+ // Place the RGB masks as the first 3 doublewords in the palette area
+ for(int i = 0; i < 3; i++)
+ pvi->TrueColorInfo.dwBitMasks[i] = bits565[i];
+
+ pvi->bmiHeader.biCompression = BI_BITFIELDS;
+ pvi->bmiHeader.biBitCount = 16;
+ break;
+ }
+
+ case 3:
+ { // 16 bits per pixel RGB555
+
+ // Place the RGB masks as the first 3 doublewords in the palette area
+ for(int i = 0; i < 3; i++)
+ pvi->TrueColorInfo.dwBitMasks[i] = bits555[i];
+
+ pvi->bmiHeader.biCompression = BI_BITFIELDS;
+ pvi->bmiHeader.biBitCount = 16;
+ break;
+ }
+
+ case 4:
+ { // 8 bit palettised
+
+ pvi->bmiHeader.biCompression = BI_RGB;
+ pvi->bmiHeader.biBitCount = 8;
+ pvi->bmiHeader.biClrUsed = iPALETTE_COLORS;
+ break;
+ }
+ }
+
+ // Adjust the parameters common to all formats
+ pvi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ pvi->bmiHeader.biWidth = m_iImageWidth;
+ pvi->bmiHeader.biHeight = m_iImageHeight;
+ pvi->bmiHeader.biPlanes = 1;
+ pvi->bmiHeader.biSizeImage = GetBitmapSize(&pvi->bmiHeader);
+ pvi->bmiHeader.biClrImportant = 0;
+
+ SetRectEmpty(&(pvi->rcSource)); // we want the whole image area rendered.
+ SetRectEmpty(&(pvi->rcTarget)); // no particular destination rectangle
+
+ pmt->SetType(&MEDIATYPE_Video);
+ pmt->SetFormatType(&FORMAT_VideoInfo);
+ pmt->SetTemporalCompression(FALSE);
+
+ // Work out the GUID for the subtype from the header info.
+ const GUID SubTypeGUID = GetBitmapSubtype(&pvi->bmiHeader);
+ pmt->SetSubtype(&SubTypeGUID);
+ pmt->SetSampleSize(pvi->bmiHeader.biSizeImage);
+
+ return NOERROR;
+
+} // GetMediaType
+
+
+//
+// CheckMediaType
+//
+// We will accept 8, 16, 24 or 32 bit video formats, in any
+// image size that gives room to bounce.
+// Returns E_INVALIDARG if the mediatype is not acceptable
+//
+HRESULT CPushPinDesktop::CheckMediaType(const CMediaType *pMediaType)
+{
+ CheckPointer(pMediaType,E_POINTER);
+
+ if((*(pMediaType->Type()) != MEDIATYPE_Video) || // we only output video
+ !(pMediaType->IsFixedSize())) // in fixed size samples
+ {
+ return E_INVALIDARG;
+ }
+
+ // Check for the subtypes we support
+ const GUID *SubType = pMediaType->Subtype();
+ if (SubType == NULL)
+ return E_INVALIDARG;
+
+ if( (*SubType != MEDIASUBTYPE_RGB24)
+#if 0
+ && (*SubType != MEDIASUBTYPE_RGB565)
+ && (*SubType != MEDIASUBTYPE_RGB555)
+ && (*SubType != MEDIASUBTYPE_RGB32)
+ && (*SubType != MEDIASUBTYPE_RGB8)
+#endif
+ )
+ {
+ return E_INVALIDARG;
+ }
+
+ // Get the format area of the media type
+ VIDEOINFO *pvi = (VIDEOINFO *) pMediaType->Format();
+
+ if(pvi == NULL)
+ return E_INVALIDARG;
+
+ // Check if the image width & height have changed
+ if( pvi->bmiHeader.biWidth != m_iImageWidth ||
+ abs(pvi->bmiHeader.biHeight) != m_iImageHeight)
+ {
+ // If the image width/height is changed, fail CheckMediaType() to force
+ // the renderer to resize the image.
+ return E_INVALIDARG;
+ }
+
+ // Don't accept formats with negative height, which would cause the desktop
+ // image to be displayed upside down.
+ if (pvi->bmiHeader.biHeight < 0)
+ return E_INVALIDARG;
+
+ return S_OK; // This format is acceptable.
+
+} // CheckMediaType
+
+
+//
+// DecideBufferSize
+//
+// This will always be called after the format has been sucessfully
+// negotiated. So we have a look at m_mt to see what size image we agreed.
+// Then we can ask for buffers of the correct size to contain them.
+//
+HRESULT CPushPinDesktop::DecideBufferSize(IMemAllocator *pAlloc,
+ ALLOCATOR_PROPERTIES *pProperties)
+{
+ CheckPointer(pAlloc,E_POINTER);
+ CheckPointer(pProperties,E_POINTER);
+
+ CAutoLock cAutoLock(m_pFilter->pStateLock());
+ HRESULT hr = NOERROR;
+
+ VIDEOINFO *pvi = (VIDEOINFO *) m_mt.Format();
+ pProperties->cBuffers = 1;
+ pProperties->cbBuffer = pvi->bmiHeader.biSizeImage;
+
+ ASSERT(pProperties->cbBuffer);
+
+ // Ask the allocator to reserve us some sample memory. NOTE: the function
+ // can succeed (return NOERROR) but still not have allocated the
+ // memory that we requested, so we must check we got whatever we wanted.
+ ALLOCATOR_PROPERTIES Actual;
+ hr = pAlloc->SetProperties(pProperties,&Actual);
+ if(FAILED(hr))
+ {
+ return hr;
+ }
+
+ // Is this allocator unsuitable?
+ if(Actual.cbBuffer < pProperties->cbBuffer)
+ {
+ return E_FAIL;
+ }
+
+ // Make sure that we have only 1 buffer (we erase the ball in the
+ // old buffer to save having to zero a 200k+ buffer every time
+ // we draw a frame)
+ ASSERT(Actual.cBuffers == 1);
+ return NOERROR;
+
+} // DecideBufferSize
+
+
+//
+// SetMediaType
+//
+// Called when a media type is agreed between filters
+//
+HRESULT CPushPinDesktop::SetMediaType(const CMediaType *pMediaType)
+{
+ CAutoLock cAutoLock(m_pFilter->pStateLock());
+
+ // Pass the call up to my base class
+ HRESULT hr = CSourceStream::SetMediaType(pMediaType);
+
+ if(SUCCEEDED(hr))
+ {
+ VIDEOINFO * pvi = (VIDEOINFO *) m_mt.Format();
+ if (pvi == NULL)
+ return E_UNEXPECTED;
+
+ switch(pvi->bmiHeader.biBitCount)
+ {
+ case 8: // 8-bit palettized
+ case 16: // RGB565, RGB555
+ case 24: // RGB24
+ case 32: // RGB32
+ // Save the current media type and bit depth
+ m_MediaType = *pMediaType;
+ m_nCurrentBitDepth = pvi->bmiHeader.biBitCount;
+ hr = S_OK;
+ break;
+
+ default:
+ // We should never agree any other media types
+ ASSERT(FALSE);
+ hr = E_INVALIDARG;
+ break;
+ }
+ }
+
+ return hr;
+
+} // SetMediaType
+
+
+// This is where we insert the DIB bits into the video stream.
+// FillBuffer is called once for every sample in the stream.
+HRESULT CPushPinDesktop::FillBuffer(IMediaSample *pSample)
+{
+ BYTE *pData;
+ long cbData;
+
+ CheckPointer(pSample, E_POINTER);
+
+ CAutoLock cAutoLockShared(&m_cSharedState);
+
+ // Access the sample's data buffer
+ pSample->GetPointer(&pData);
+ cbData = pSample->GetSize();
+
+ // Check that we're still using video
+ ASSERT(m_mt.formattype == FORMAT_VideoInfo);
+
+ VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)m_mt.pbFormat;
+
+ // Copy the DIB bits over into our filter's output buffer.
+ // Since sample size may be larger than the image size, bound the copy size.
+ int nSize = min(pVih->bmiHeader.biSizeImage, (DWORD) cbData);
+ HDIB hDib = CopyScreenToBitmap(&m_rScreen, pData, (BITMAPINFO *) &(pVih->bmiHeader));
+
+ if (hDib)
+ DeleteObject(hDib);
+
+ // Set the timestamps that will govern playback frame rate.
+ // If this file is getting written out as an AVI,
+ // then you'll also need to configure the AVI Mux filter to
+ // set the Average Time Per Frame for the AVI Header.
+ // The current time is the sample's start.
+ REFERENCE_TIME rtStart = m_iFrameNumber * m_rtFrameLength;
+ REFERENCE_TIME rtStop = rtStart + m_rtFrameLength;
+
+ pSample->SetTime(&rtStart, &rtStop);
+ m_iFrameNumber++;
+
+ // Set TRUE on every sample for uncompressed frames
+ pSample->SetSyncPoint(TRUE);
+
+ return S_OK;
+}
+
+
+
+/**********************************************
+ *
+ * CPushSourceDesktop Class
+ *
+ **********************************************/
+
+CPushSourceDesktop::CPushSourceDesktop(IUnknown *pUnk, HRESULT *phr)
+ : CSource(NAME("PushSourceDesktop"), pUnk, CLSID_PushSourceDesktop)
+{
+ // The pin magically adds itself to our pin array.
+ m_pPin = new CPushPinDesktop(phr, this);
+
+ if (phr)
+ {
+ if (m_pPin == NULL)
+ *phr = E_OUTOFMEMORY;
+ else
+ *phr = S_OK;
+ }
+}
+
+
+CPushSourceDesktop::~CPushSourceDesktop()
+{
+ if (m_pPin)
+ {
+ delete m_pPin;
+ m_pPin = NULL;
+ }
+}
+
+
+CUnknown * WINAPI CPushSourceDesktop::CreateInstance(IUnknown *pUnk, HRESULT *phr)
+{
+ CPushSourceDesktop *pNewFilter = new CPushSourceDesktop(pUnk, phr );
+
+ if (phr)
+ {
+ if (pNewFilter == NULL)
+ *phr = E_OUTOFMEMORY;
+ else
+ *phr = S_OK;
+ }
+ return pNewFilter;
+
+}
+
+HRESULT CPushSourceDesktop::SetSrcHwnd(HWND hWnd)
+{
+ if (m_pPin)
+ {
+ return m_pPin->SetSrcHwnd(hWnd);
+ }
+ return E_FAIL;
+}
+
+#endif /* _WIN32_WCE */
diff --git a/plugins/pluginDirectShow/internals/DSScreenCastGraph.cxx b/plugins/pluginDirectShow/internals/DSScreenCastGraph.cxx
new file mode 100644
index 0000000..b425d65
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/DSScreenCastGraph.cxx
@@ -0,0 +1,257 @@
+#if !defined(_WIN32_WCE)
+/* Copyright (C) 2014 Mamadou DIOP
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#include <streams.h>
+#include "internals/DSScreenCastGraph.h"
+#include "internals/DSPushSource.h"
+#include "internals/DSUtils.h"
+#include "internals/DSCaptureUtils.h"
+
+#include "tsk_debug.h"
+
+#include <iostream>
+
+using namespace std;
+
+DSScreenCastGraph::DSScreenCastGraph(ISampleGrabberCB* callback, HRESULT *hr)
+: DSBaseCaptureGraph(callback, hr)
+{
+ this->grabberCallback = callback;
+
+ this->captureFormat = NULL;
+ this->captureGraphBuilder = NULL;
+ this->graphBuilder = NULL;
+
+ this->sourceFilter = NULL;
+ this->sampleGrabberFilter = NULL;
+
+ this->nullRendererFilter = NULL;
+ this->grabberController = NULL;
+ this->mediaController = NULL;
+ this->mediaEventController = NULL;
+
+ this->running = FALSE;
+ this->paused = FALSE;
+
+ *hr = this->createCaptureGraph();
+}
+
+DSScreenCastGraph::~DSScreenCastGraph()
+{
+ SAFE_RELEASE(this->mediaEventController);
+ SAFE_RELEASE(this->mediaController);
+ SAFE_RELEASE(this->grabberController);
+
+ SAFE_RELEASE(this->nullRendererFilter);
+ SAFE_RELEASE(this->sampleGrabberFilter);
+
+ SAFE_RELEASE(this->graphBuilder);
+ SAFE_RELEASE(this->captureGraphBuilder);
+
+ SAFE_RELEASE(this->sourceFilter);
+}
+
+HRESULT DSScreenCastGraph::setParameters(DSCaptureFormat *format, int framerate)
+{
+ return S_OK;
+}
+
+#ifdef _WIN32_WCE
+# include <tinydshow/wce/DSInxbNullFilter.h>
+#endif
+
+HRESULT DSScreenCastGraph::connect()
+{
+ HRESULT hr;
+
+ if (!this->sourceFilter){
+ TSK_DEBUG_ERROR("Invalid source filter");
+ return E_FAIL;
+ }
+#if 0
+ if (!this->captureFormat){
+ TSK_DEBUG_ERROR("Invalid capture format");
+ return E_FAIL;
+ }
+#endif
+
+ hr = ConnectFilters(this->graphBuilder, this->sourceFilter, this->sampleGrabberFilter); if(FAILED(hr)) { TSK_DEBUG_ERROR("ConnectFilters failed"); return hr; }
+ hr = ConnectFilters(this->graphBuilder, this->sampleGrabberFilter, this->nullRendererFilter); if(FAILED(hr)) { TSK_DEBUG_ERROR("ConnectFilters failed"); return hr; }
+
+ return hr;
+}
+
+HRESULT DSScreenCastGraph::disconnect()
+{
+ HRESULT hr;
+
+ if (!this->sourceFilter)
+ {
+ return E_FAIL;
+ }
+#if 0
+ if (!this->captureFormat)
+ {
+ return E_FAIL;
+ }
+#endif
+
+ hr = DisconnectFilters(this->graphBuilder, this->sourceFilter, this->sampleGrabberFilter);
+ hr = DisconnectFilters(this->graphBuilder, this->sampleGrabberFilter, this->nullRendererFilter);
+
+ return hr;
+}
+
+HRESULT DSScreenCastGraph::start()
+{
+ HRESULT hr;
+
+ if (isRunning() && !isPaused())
+ {
+ return S_OK;
+ }
+
+ hr = this->mediaController->Run();
+ if (!SUCCEEDED(hr))
+ {
+ TSK_DEBUG_ERROR("DSScreenCastGraph::mediaController->Run() has failed with %ld", hr);
+ return hr;
+ }
+ this->running = true;
+ return hr;
+}
+
+HRESULT DSScreenCastGraph::pause()
+{
+ HRESULT hr = S_OK;
+ if (isRunning())
+ {
+ hr = this->mediaController->Pause();
+ if (SUCCEEDED(hr))
+ {
+ this->paused = TRUE;
+ }
+ }
+ return hr;
+}
+
+HRESULT DSScreenCastGraph::stop()
+{
+ if (!this->running)
+ {
+ return S_OK;
+ }
+
+ HRESULT hr;
+ hr = this->mediaController->Stop();
+ if (FAILED(hr))
+ {
+ TSK_DEBUG_ERROR("DSScreenCastGraph::mediaController->Stop() has failed with %ld", hr);
+ }
+ this->running = false;
+ this->paused = false;
+ return hr;
+}
+
+bool DSScreenCastGraph::isRunning()
+{
+ return this->running;
+}
+
+bool DSScreenCastGraph::isPaused()
+{
+ return this->paused;
+}
+
+HRESULT DSScreenCastGraph::getConnectedMediaType(AM_MEDIA_TYPE *mediaType)
+{
+ return this->grabberController->GetConnectedMediaType(mediaType);
+}
+
+HRESULT DSScreenCastGraph::createCaptureGraph()
+{
+ HRESULT hr;
+
+ // Create capture graph builder
+ hr = COCREATE(CLSID_CaptureGraphBuilder2, IID_ICaptureGraphBuilder2, this->captureGraphBuilder);
+ if(FAILED(hr)) return hr;
+
+ // Create the graph builder
+ hr = COCREATE(CLSID_FilterGraph, IID_IGraphBuilder, this->graphBuilder);
+ if(FAILED(hr)) return hr;
+
+ // Initialize the Capture Graph Builder.
+ hr = this->captureGraphBuilder->SetFiltergraph(this->graphBuilder);
+ if(FAILED(hr)) return hr;
+
+ // Create source filter
+ LPUNKNOWN pUnk = NULL;
+ this->sourceFilter = (CPushSourceDesktop*)CPushSourceDesktop::CreateInstance(pUnk, &hr);
+ if(FAILED(hr)) return hr;
+ this->sourceFilter->AddRef();
+
+ // Create the sample grabber filter
+ hr = COCREATE(CLSID_SampleGrabber, IID_IBaseFilter, this->sampleGrabberFilter);
+ if(FAILED(hr)) return hr;
+
+ // Create the NULL renderer
+ hr = COCREATE(CLSID_NullRenderer, IID_IBaseFilter, this->nullRendererFilter);
+ if(FAILED(hr)) return hr;
+
+ // Add source filter to the graph
+ hr = this->graphBuilder->AddFilter(this->sourceFilter, FILTER_SCREENCAST);
+ if(FAILED(hr)) return hr;
+
+ // Add sample grabber to the graph
+ hr = this->graphBuilder->AddFilter(this->sampleGrabberFilter, FITLER_SAMPLE_GRABBER);
+ if(FAILED(hr)) return hr;
+
+ // Add null renderer to the graph
+ hr = this->graphBuilder->AddFilter(this->nullRendererFilter, FILTER_NULL_RENDERER);
+ if(FAILED(hr)) return hr;
+
+ // Find media control
+ hr = QUERY(this->graphBuilder, IID_IMediaControl, this->mediaController);
+ if(FAILED(hr)) return hr;
+
+ // Create the sample grabber controller
+ hr = QUERY(this->sampleGrabberFilter, IID_ISampleGrabber, this->grabberController);
+ if(FAILED(hr)) return hr;
+
+ // Set the sample grabber media type (RGB24)
+ // TODO : CHECK
+ AM_MEDIA_TYPE mt;
+ ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
+ mt.majortype = MEDIATYPE_Video;
+ mt.subtype = MEDIASUBTYPE_RGB24;
+ mt.formattype = FORMAT_VideoInfo;
+
+ hr = this->grabberController->SetMediaType(&mt);
+ if(FAILED(hr)) return hr;
+
+ // Set sample grabber media type
+ this->grabberController->SetOneShot(FALSE);
+ this->grabberController->SetBufferSamples(FALSE);
+
+ hr = this->grabberController->SetCallback(this->grabberCallback, 1);
+ if(FAILED(hr)) return hr;
+
+ return hr;
+}
+
+#endif /* _WIN32_WCE */ \ No newline at end of file
diff --git a/plugins/pluginDirectShow/internals/DSScreenCastGraph.h b/plugins/pluginDirectShow/internals/DSScreenCastGraph.h
new file mode 100644
index 0000000..d201668
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/DSScreenCastGraph.h
@@ -0,0 +1,160 @@
+/* Copyright (C) 2014 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#ifndef PLUGIN_DSHOW_DSSCREENCAST_H
+#define PLUGIN_DSHOW_DSSCREENCAST_H
+
+#include "plugin_dshow_config.h"
+#include "internals/DSBaseCaptureGraph.h"
+
+#include <control.h>
+#include <vector>
+#include <qedit.h>
+
+
+class CPushSourceDesktop;
+
+class DSScreenCastGraph : public DSBaseCaptureGraph
+{
+public:
+ DSScreenCastGraph(ISampleGrabberCB* callback, HRESULT *hr);
+ virtual ~DSScreenCastGraph();
+
+ std::vector<DSCaptureFormat> *getFormats() { return &this->supportedFormats; };
+
+ virtual HRESULT setSource(const std::string &devicePath) { return S_OK; }
+ HRESULT setParameters(DSCaptureFormat *format, int framerate);
+
+ HRESULT connect();
+ HRESULT disconnect();
+
+ HRESULT start();
+ HRESULT stop();
+ HRESULT pause();
+ bool isRunning();
+ bool isPaused();
+
+ HRESULT getConnectedMediaType(AM_MEDIA_TYPE *mediaType);
+
+ virtual std::string getDeviceId() const { return std::string("screencast"); }
+
+private:
+ HRESULT createCaptureGraph();
+
+private:
+ ISampleGrabberCB *grabberCallback;
+
+ ICaptureGraphBuilder2 *captureGraphBuilder;
+ IGraphBuilder *graphBuilder;
+
+ CPushSourceDesktop *sourceFilter;
+ IBaseFilter *nullRendererFilter;
+ IBaseFilter *sampleGrabberFilter;
+
+ ISampleGrabber *grabberController;
+
+ IMediaControl *mediaController;
+ IMediaEventEx *mediaEventController;
+
+ std::vector<DSCaptureFormat> supportedFormats;
+ DSCaptureFormat *captureFormat;
+
+ bool running;
+ bool paused;
+};
+
+#endif /* PLUGIN_DSHOW_DSSCREENCAST_H */
+/* Copyright (C) 2014 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#ifndef PLUGIN_DSHOW_DSSCREENCAST_H
+#define PLUGIN_DSHOW_DSSCREENCAST_H
+
+#include "plugin_dshow_config.h"
+#include "internals/DSBaseCaptureGraph.h"
+
+#include <control.h>
+#include <vector>
+#include <qedit.h>
+
+
+class CPushSourceDesktop;
+
+class DSScreenCastGraph : public DSBaseCaptureGraph
+{
+public:
+ DSScreenCastGraph(ISampleGrabberCB* callback, HRESULT *hr);
+ virtual ~DSScreenCastGraph();
+
+ std::vector<DSCaptureFormat> *getFormats() { return &this->supportedFormats; };
+
+ virtual HRESULT setSource(const std::string &devicePath) { return S_OK; }
+ HRESULT setParameters(DSCaptureFormat *format, int framerate);
+
+ HRESULT connect();
+ HRESULT disconnect();
+
+ HRESULT start();
+ HRESULT stop();
+ HRESULT pause();
+ bool isRunning();
+ bool isPaused();
+
+ HRESULT getConnectedMediaType(AM_MEDIA_TYPE *mediaType);
+
+ virtual std::string getDeviceId() const { return std::string("screencast"); }
+
+private:
+ HRESULT createCaptureGraph();
+
+private:
+ ISampleGrabberCB *grabberCallback;
+
+ ICaptureGraphBuilder2 *captureGraphBuilder;
+ IGraphBuilder *graphBuilder;
+
+ CPushSourceDesktop *sourceFilter;
+ IBaseFilter *nullRendererFilter;
+ IBaseFilter *sampleGrabberFilter;
+
+ ISampleGrabber *grabberController;
+
+ IMediaControl *mediaController;
+ IMediaEventEx *mediaEventController;
+
+ std::vector<DSCaptureFormat> supportedFormats;
+ DSCaptureFormat *captureFormat;
+
+ bool running;
+ bool paused;
+};
+
+#endif /* PLUGIN_DSHOW_DSSCREENCAST_H */
diff --git a/plugins/pluginDirectShow/internals/DSUtils.cxx b/plugins/pluginDirectShow/internals/DSUtils.cxx
new file mode 100644
index 0000000..913c081
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/DSUtils.cxx
@@ -0,0 +1,365 @@
+/* Copyright (C) 2011-2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#include "internals/DSUtils.h"
+
+#if defined (_WIN32_WCE)
+#include <atlbase.h>
+#include <atlstr.h>
+#else
+#include <atlconv.h>
+#include <d3d9.h>
+#endif
+
+#include "tsk_debug.h"
+
+HWND GetMainWindow()
+{
+ HWND hWnd;
+ if (!(hWnd = GetActiveWindow())) {
+ if (!(hWnd = GetForegroundWindow())) {
+#if !defined(_WIN32_WCE)
+ if (!(hWnd = GetConsoleWindow())) {
+ return NULL;
+ }
+#endif
+ }
+ }
+ return hWnd;
+}
+
+bool IsMainThread()
+{
+ HWND hWnd = GetMainWindow();
+ if (hWnd) {
+ DWORD mainTid = GetWindowThreadProcessId(hWnd, NULL);
+ DWORD currentTid = GetCurrentThreadId();
+ return (mainTid == currentTid);
+ }
+ return false;
+}
+
+bool IsD3D9Supported()
+{
+#if defined(_WIN32_WCE)
+ return false;
+#else
+ static bool g_bChecked = false;
+ static bool g_bSupported = false;
+
+ if (g_bChecked) {
+ return g_bSupported;
+ }
+ g_bChecked = true;
+ HRESULT hr = S_OK;
+ IDirect3D9* pD3D = NULL;
+ D3DDISPLAYMODE mode = { 0 };
+ D3DPRESENT_PARAMETERS pp = {0};
+ IDirect3DDevice9* pDevice = NULL;
+
+ if (!(pD3D = Direct3DCreate9(D3D_SDK_VERSION))) {
+ hr = E_OUTOFMEMORY;
+ goto bail;
+ }
+
+ hr = pD3D->GetAdapterDisplayMode(
+ D3DADAPTER_DEFAULT,
+ &mode
+ );
+ if (FAILED(hr)) {
+ goto bail;
+ }
+
+ hr = pD3D->CheckDeviceType(
+ D3DADAPTER_DEFAULT,
+ D3DDEVTYPE_HAL,
+ mode.Format,
+ D3DFMT_X8R8G8B8,
+ TRUE // windowed
+ );
+ if (FAILED(hr)) {
+ goto bail;
+ }
+ pp.BackBufferFormat = D3DFMT_X8R8G8B8;
+ pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
+ pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
+ pp.Windowed = TRUE;
+ pp.hDeviceWindow = GetDesktopWindow();
+ hr = pD3D->CreateDevice(
+ D3DADAPTER_DEFAULT,
+ D3DDEVTYPE_HAL,
+ pp.hDeviceWindow,
+ D3DCREATE_HARDWARE_VERTEXPROCESSING,
+ &pp,
+ &pDevice
+ );
+ if (FAILED(hr)) {
+ goto bail;
+ }
+
+ // Everythings is OK
+ g_bSupported = true;
+ TSK_DEBUG_INFO("D3D9 supported");
+
+bail:
+ if (!g_bSupported) {
+ TSK_DEBUG_WARN("D3D9 not supported");
+ }
+ SAFE_RELEASE(pDevice);
+ SAFE_RELEASE(pD3D);
+ return g_bSupported;
+#endif /* _WIN32_WCE */
+}
+
+IPin *GetPin(IBaseFilter *filter, PIN_DIRECTION direction)
+{
+ IEnumPins *enumPins = NULL;
+ IPin *pin = NULL;
+
+ HRESULT hr = filter->EnumPins(&enumPins);
+ if(!enumPins){
+ return NULL;
+ }
+
+ for(;;){
+ ULONG fetched = 0;
+ PIN_DIRECTION pinDir = PIN_DIRECTION(-1);
+ pin = NULL;
+
+ if (FAILED(enumPins->Next(1, &pin, &fetched))){
+ enumPins->Release();
+ return NULL;
+ }
+
+ if (fetched == 1 && pin){
+ pin->QueryDirection(&pinDir);
+ if(pinDir == direction){
+ break;
+ }
+ pin->Release();
+ }
+ }
+
+ enumPins->Release();
+ return pin;
+}
+
+HRESULT ConnectFilters(IGraphBuilder *graphBuilder, IBaseFilter *source, IBaseFilter *destination, AM_MEDIA_TYPE *mediaType)
+{
+ HRESULT hr;
+
+ IPin *outPin = GetPin(source, PINDIR_OUTPUT);
+ IPin *inPin = GetPin(destination, PINDIR_INPUT);
+
+ if (mediaType != NULL){
+ hr = graphBuilder->ConnectDirect(outPin, inPin, mediaType);
+ }
+ else{
+ hr = graphBuilder->Connect(outPin, inPin);
+ }
+
+ SAFE_RELEASE(outPin);
+ SAFE_RELEASE(inPin);
+
+ return hr;
+}
+
+HRESULT DisconnectFilters(IGraphBuilder *graphBuilder, IBaseFilter *source, IBaseFilter *destination)
+{
+ HRESULT hr;
+
+ IPin *outPin = GetPin(source, PINDIR_OUTPUT);
+ IPin *inPin = GetPin(destination, PINDIR_INPUT);
+
+ if (inPin){
+ hr = graphBuilder->Disconnect(inPin);
+ }
+
+ if (outPin){
+ hr = graphBuilder->Disconnect(outPin);
+ }
+
+ SAFE_RELEASE(outPin);
+ SAFE_RELEASE(inPin);
+
+ return hr;
+}
+
+bool DisconnectAllFilters(IGraphBuilder *graphBuilder)
+{
+ IEnumFilters* filterEnum = NULL;
+ IBaseFilter* currentFilter = NULL;
+ ULONG fetched;
+ HRESULT hr;
+
+ hr = graphBuilder->EnumFilters(&filterEnum);
+ if (FAILED(hr)) {
+ SAFE_RELEASE(filterEnum);
+ return false;
+ }
+
+ while(filterEnum->Next(1, &currentFilter, &fetched) == S_OK){
+ hr = DisconnectFilters(graphBuilder, currentFilter, currentFilter);
+ SAFE_RELEASE(currentFilter);
+ }
+ SAFE_RELEASE(filterEnum);
+ SAFE_RELEASE(currentFilter);
+ return true;
+}
+
+bool RemoveAllFilters(IGraphBuilder *graphBuilder)
+{
+ IEnumFilters* filterEnum = NULL;
+ IBaseFilter* currentFilter = NULL;
+ ULONG fetched;
+ HRESULT hr;
+
+ hr = graphBuilder->EnumFilters(&filterEnum);
+ if (FAILED(hr)) return false;
+
+ while(filterEnum->Next(1, &currentFilter, &fetched) == S_OK){
+ hr = graphBuilder->RemoveFilter(currentFilter);
+ if (FAILED(hr)){
+ SAFE_RELEASE(filterEnum);
+ return false;
+ }
+ SAFE_RELEASE(currentFilter);
+ filterEnum->Reset();
+ }
+
+ SAFE_RELEASE(filterEnum);
+ SAFE_RELEASE(currentFilter);
+ return true;
+}
+
+
+#include "internals/DSDisplay.h"
+#include "internals/DSGrabber.h"
+
+#define WM_CREATE_DISPLAY_ON_UI_THREAD (WM_USER + 101)
+#define WM_CREATE_GRABBER_ON_UI_THREAD (WM_CREATE_DISPLAY_ON_UI_THREAD + 1)
+#define WM_CREATE_ON_UI_THREAD_TIMEOUT 1000
+
+// C Callback that dispatch event to create display on UI thread
+static LRESULT CALLBACK __create__WndProcWindow(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ HANDLE* event = reinterpret_cast<HANDLE*>(wParam);
+ BOOL* isScreenCast = reinterpret_cast<BOOL*>(GetProp(hWnd, TEXT("screnCast")));
+
+ if(event && lParam){
+ switch(uMsg){
+ case WM_CREATE_DISPLAY_ON_UI_THREAD:
+ {
+ HRESULT hr;
+ DSDisplay** ppDisplay = reinterpret_cast<DSDisplay**>(lParam);
+ *ppDisplay = new DSDisplay(&hr);
+ SetEvent(event);
+ break;
+ }
+ case WM_CREATE_GRABBER_ON_UI_THREAD:
+ {
+ HRESULT hr;
+ DSGrabber** ppGrabber = reinterpret_cast<DSGrabber**>(lParam);
+ *ppGrabber = new DSGrabber(&hr, *isScreenCast);
+ SetEvent(event);
+ break;
+ }
+ }
+ }
+ return DefWindowProc(hWnd, uMsg, wParam, lParam);
+}
+
+int createOnCurrentThead(HWND hWnd, void** ppRet, BOOL display, BOOL screnCast)
+{
+ HRESULT hr;
+ if(display) *ppRet = new DSDisplay(&hr);
+ else *ppRet = new DSGrabber(&hr, screnCast);
+ if(FAILED(hr)){
+ TSK_DEBUG_ERROR("Failed to created DirectShow %s", display ? "Display" : "Grabber");
+ SAFE_DELETE_PTR(*ppRet);
+ return -2;
+ }
+ return 0;
+}
+
+int createOnUIThead(HWND hWnd, void** ppRet, BOOL display, BOOL screnCast)
+{
+ static BOOL __isScreenCastFalse = FALSE;
+ static BOOL __isScreenCastTrue = TRUE;
+ if(!ppRet){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if (IsMainThread()) {
+ return createOnCurrentThead(hWnd, ppRet, display, screnCast);
+ }
+ else{
+ TSK_DEBUG_INFO("Create DirectShow element on worker thread");
+ HANDLE event = NULL;
+ int ret = 0;
+ DWORD retWait, retryCount = 3;
+
+ if(!hWnd){
+ if (!(hWnd = FindWindow(NULL, TEXT("Boghe - IMS/RCS Client")))) {
+ if(!(hWnd = GetMainWindow())){
+ TSK_DEBUG_ERROR("No Window handle could be used");
+ return -2;
+ }
+ }
+ }
+#if defined(_WIN32_WCE)
+ WNDPROC wndProc = (WNDPROC) SetWindowLong(hWnd, GWL_WNDPROC, (LONG) __create__WndProcWindow);
+#else
+ WNDPROC wndProc = (WNDPROC) SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR) __create__WndProcWindow);
+#endif
+ if (!wndProc) {
+ TSK_DEBUG_ERROR("SetWindowLongPtr() failed with errcode=%d", GetLastError());
+ return createOnCurrentThead(hWnd, ppRet, display, screnCast);
+ }
+
+ if (!(event = CreateEvent(NULL, TRUE, FALSE, NULL))) {
+ TSK_DEBUG_ERROR("Failed to create new event");
+ ret = -4; goto bail;
+ }
+ SetProp(hWnd, TEXT("screnCast"), screnCast ? &__isScreenCastTrue : &__isScreenCastFalse);
+ if (!PostMessage(hWnd, display ? WM_CREATE_DISPLAY_ON_UI_THREAD : WM_CREATE_GRABBER_ON_UI_THREAD, reinterpret_cast<WPARAM>(event), reinterpret_cast<LPARAM>(ppRet))) {
+ TSK_DEBUG_ERROR("PostMessageA() failed");
+ ret = -5; goto bail;
+ }
+
+ do {
+ retWait = WaitForSingleObject(event, WM_CREATE_ON_UI_THREAD_TIMEOUT);
+ }
+ while (retryCount-- > 0 && (retWait == WAIT_TIMEOUT));
+
+ bail:
+ // restore
+ if (hWnd && wndProc) {
+#if defined(_WIN32_WCE)
+ SetWindowLong(hWnd, GWL_WNDPROC, (LONG)wndProc);
+#else
+ SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)wndProc);
+#endif
+ }
+ if (event) {
+ CloseHandle(event);
+ }
+
+ return ret;
+ }
+} \ No newline at end of file
diff --git a/plugins/pluginDirectShow/internals/DSUtils.h b/plugins/pluginDirectShow/internals/DSUtils.h
new file mode 100644
index 0000000..09690ea
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/DSUtils.h
@@ -0,0 +1,82 @@
+/* Copyright (C) 2011-2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#ifndef PLUGIN_DSHOW_DUTILS_H
+#define PLUGIN_DSHOW_DUTILS_H
+
+#include "plugin_dshow_config.h"
+
+#include <strmif.h>
+
+// --------------------------------------------------------------------------------
+
+#define SAFE_RELEASE(x) if ((x)) { (x)->Release(); (x) = NULL; }
+#define SAFE_DELETE_PTR(x) if ((x)) { delete (x); (x) = NULL; }
+#define SAFE_DELETE_ARRAY(x) if ((x)) { delete[] (x); (x) = NULL; }
+// In CHECK_HR(x) When (x) is a function it will be executed twice when used in "TSK_DEBUG_ERROR(x)" and "If(x)"
+#define CHECK_HR(x) { HRESULT __hr__ = (x); if (FAILED(__hr__)) { TSK_DEBUG_ERROR("Operation Failed (%08x)", __hr__); goto bail; } }
+
+#define DS_NANOS_TO_100NS(NANOS) (((LONGLONG)(NANOS)) / 100ui64)
+#define DS_MICROS_TO_100NS(MICROS) (((LONGLONG)(MICROS)) * 10ui64)
+#define DS_MILLIS_TO_100NS(MILLIS) (((LONGLONG)(MILLIS)) * 10000ui64)
+#define DS_SECONDS_TO_100NS(SEC) (((LONGLONG)(SEC)) * 10000000ui64)
+#define DS_SECONDS_FROM_100NS(SEC) (10000000ui64/(SEC))
+
+#define COCREATE(cls, iid, target) \
+ CoCreateInstance(cls, NULL, CLSCTX_INPROC_SERVER, iid, reinterpret_cast<void**>(&target))
+#define QUERY(source, iid, target) \
+ source->QueryInterface(iid, reinterpret_cast<void**>(&target))
+
+// --------------------------------------------------------------------------------
+
+
+#define FILTER_WEBCAM _T("WEBCAM")
+#define FILTER_SCREENCAST _T("SCREENCAST")
+#define FILTER_FRAMERATE _T("TDSHOW_FRAMERATE")
+#define FILTER_OUTPUT _T("TDSHOW_OUTPUT")
+#define FITLER_SAMPLE_GRABBER _T("SAMPLE_GRABBER")
+#define FILTER_AVI_DECOMPRESSOR _T("AVI_DECOMPRESSOR")
+
+#define FILTER_COLORSPACE_CONVERTOR _T("COLORSPACE_CONVERTOR")
+#define FILTER_NULL_RENDERER _T("NULL_RENDERER")
+#define FILTER_VIDEO_RENDERER _T("VIDEO_RENDERER")
+#define FILTER_VIDEO_MIXING_RENDERER _T("VIDEO_MIXING_RENDERER")
+#define FILTER_COLOR_CONVERTOR_565 _T("COLOR_CONVERTOR_565")
+
+// --------------------------------------------------------------------------------
+
+HWND GetMainWindow();
+
+bool IsMainThread();
+
+bool IsD3D9Supported();
+
+IPin *GetPin(IBaseFilter *pFilter, PIN_DIRECTION dir);
+
+HRESULT ConnectFilters(IGraphBuilder *graphBuilder, IBaseFilter *source, IBaseFilter *destination, AM_MEDIA_TYPE *mediaType = NULL);
+
+HRESULT DisconnectFilters(IGraphBuilder *graphBuilder, IBaseFilter *source, IBaseFilter *destination);
+
+bool DisconnectAllFilters(IGraphBuilder *graphBuilder);
+
+bool RemoveAllFilters(IGraphBuilder *graphBuilder);
+
+int createOnCurrentThead(HWND hWnd, void** ppRet, BOOL display, BOOL screnCast);
+
+int createOnUIThead(HWND hWnd, void** ppRet, BOOL display, BOOL screnCast);
+
+#endif /* PLUGIN_DSHOW_DUTILS_H */
diff --git a/plugins/pluginDirectShow/internals/Resizer.cxx b/plugins/pluginDirectShow/internals/Resizer.cxx
new file mode 100644
index 0000000..32bcfac
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/Resizer.cxx
@@ -0,0 +1,1192 @@
+/* Copyright (C) 2011-2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+/*
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ */
+#if !defined(RESIZER_DO_NOT_INCLUDE_HEADER)
+#include "internals/Resizer.h"
+#endif /* DO_NOT_INCLUDE_HEADER */
+
+
+/* stretch proportions */
+#define STRETCH_1_1 1
+#define STRETCH_1_2 2
+#define STRETCH_1_4 3
+#define STRETCH_1_N 4
+#define STRETCH_N_1 5
+#define STRETCH_4_1 6
+#define STRETCH_2_1 7
+
+void __stdcall StretchDIB(
+ LPBITMAPINFOHEADER biDst, // --> BITMAPINFO of destination
+ LPVOID lpvDst, // --> to destination bits
+ int DstX, // Destination origin - x coordinate
+ int DstY, // Destination origin - y coordinate
+ int DstXE, // x extent of the BLT
+ int DstYE, // y extent of the BLT
+ LPBITMAPINFOHEADER biSrc, // --> BITMAPINFO of source
+ LPVOID lpvSrc, // --> to source bits
+ int SrcX, // Source origin - x coordinate
+ int SrcY, // Source origin - y coordinate
+ int SrcXE, // x extent of the BLT
+ int SrcYE // y extent of the BLT
+ );
+
+/*
+* an X_FUNC is a function that copies one scanline, stretching or shrinking it
+* to fit a destination scanline. Pick an X_FUNC depending on
+* bitdepth and stretch ratio (1:1, 1:2, 1:4, 1:N, N:1, 4:1, 2:1)
+*
+* the x_fract argument is the delta fraction: it is a representation
+* of the smaller extent (whichever that is) as a fraction of the larger,
+* and is used when stretching or shrinking to advance the pointer to the
+* smaller scanline every (fract) pixels of the larger.
+* Thus if we are expanding 1:8, x_fract will be 1/8, we will advance the
+* source pointer once every 8 pixels, and thus copy each source pixel to
+* 8 dest pixels. Note that if shrinking 8:1, x_fract will still be 1/8
+* and we will use it to control advancement of the dest pointer.
+* the fraction is multiplied by 65536.
+*/
+typedef void (*X_FUNC) (LPBYTE lpSrc,
+ LPBYTE lpDst,
+ int SrcXE,
+ int DstXE,
+ int x_fract);
+
+
+void X_Stretch_1_1_8Bits(LPBYTE lpSrc, LPBYTE lpDst, int SrcXE, int DstXE, int x_fract);
+void X_Stretch_1_2_8Bits(LPBYTE lpSrc, LPBYTE lpDst, int SrcXE, int DstXE, int x_fract);
+void X_Stretch_1_4_8Bits(LPBYTE lpSrc, LPBYTE lpDst, int SrcXE, int DstXE, int x_fract);
+void X_Stretch_1_N_8Bits(LPBYTE lpSrc, LPBYTE lpDst, int SrcXE, int DstXE, int x_fract);
+void X_Stretch_N_1_8Bits(LPBYTE lpSrc, LPBYTE lpDst, int SrcXE, int DstXE, int x_fract);
+
+void X_Stretch_1_1_16Bits(LPBYTE lpSrc, LPBYTE lpDst, int SrcXE, int DstXE, int x_fract);
+void X_Stretch_1_2_16Bits(LPBYTE lpSrc, LPBYTE lpDst, int SrcXE, int DstXE, int x_fract);
+void X_Stretch_1_N_16Bits(LPBYTE lpSrc, LPBYTE lpDst, int SrcXE, int DstXE, int x_fract);
+void X_Stretch_N_1_16Bits(LPBYTE lpSrc, LPBYTE lpDst, int SrcXE, int DstXE, int x_fract);
+
+void X_Stretch_1_1_24Bits(LPBYTE lpSrc, LPBYTE lpDst, int SrcXE, int DstXE, int x_fract);
+void X_Stretch_1_N_24Bits(LPBYTE lpSrc, LPBYTE lpDst, int SrcXE, int DstXE, int x_fract);
+void X_Stretch_N_1_24Bits(LPBYTE lpSrc, LPBYTE lpDst, int SrcXE, int DstXE, int x_fract);
+
+void X_Stretch_1_1_32Bits(LPBYTE lpSrc, LPBYTE lpDst, int SrcXE, int DstXE, int x_fract);
+void X_Stretch_1_N_32Bits(LPBYTE lpSrc, LPBYTE lpDst, int SrcXE, int DstXE, int x_fract);
+void X_Stretch_N_1_32Bits(LPBYTE lpSrc, LPBYTE lpDst, int SrcXE, int DstXE, int x_fract);
+
+
+/*
+* Y_Stretch_* functions copy DstYE scanlines (using
+* an X_FUNC to copy each scanline) omitting or duplicating scanlines to
+* fit the destination extent. Pick a Y_ depending on the ratio
+* (1:N, N:1...)
+*/
+
+void Y_Stretch_1_N(LPBYTE lpSrc, LPBYTE lpDst, int SrcXE,int SrcYE, int DstXE,
+ int DstYE, int SrcWidth, int DstWidth, int x_fract,
+ X_FUNC x_func, int nBits);
+
+void Y_Stretch_N_1(LPBYTE lpSrc, LPBYTE lpDst, int SrcXE,int SrcYE, int DstXE,
+ int DstYE, int SrcWidth, int DstWidth, int x_fract,
+ X_FUNC x_func);
+
+/*
+* special case y-stretch functions for 1:2 in both dimensions for 8 and 16 bits
+* takes no X_FUNC arg. Will do entire stretch.
+*/
+void Stretch_1_2_8Bits(LPBYTE lpSrc, LPBYTE lpDst, int SrcXE,int SrcYE, int DstXE,
+ int DstYE, int SrcWidth, int DstWidth, int x_fract);
+
+
+void Stretch_1_2_16Bits(LPBYTE lpSrc, LPBYTE lpDst, int SrcXE,int SrcYE, int DstXE,
+ int DstYE, int SrcWidth, int DstWidth, int x_fract);
+
+/* straight copy of one scanline of count bytes */
+void X_CopyScanline(LPBYTE lpSrc, LPBYTE lpDst, int count);
+
+
+//
+// Resize function
+//
+void ResizeRGB( BITMAPINFOHEADER *pbiIn, //Src's BitMapInFoHeader
+ const unsigned char * dibBits, //Src bits
+ BITMAPINFOHEADER *pbiOut,
+ unsigned char *pFrame, //Dst bits
+ int iNewWidth, //new W in pixel
+ int iNewHeight) //new H in pixel
+{
+ StretchDIB( pbiOut, // --> BITMAPINFO of destination
+ pFrame, // --> to destination bits
+ 0, // Destination origin - x coordinate
+ 0, // Destination origin - y coordinate
+ iNewWidth, // x extent of the BLT
+ iNewHeight, // y extent of the BLT
+ pbiIn, // --> BITMAPINFO of destination
+ (void*) dibBits, // --> to source bits
+ 0, // Source origin - x coordinate
+ 0, // Source origin - y coordinate
+ pbiIn->biWidth, // x extent of the BLT
+ pbiIn->biHeight // y extent of the BLT
+ );
+
+ return;
+}
+
+
+/* -------------------------------------------------------------------- */
+
+/*
+* StretchFactor
+*
+* calculate the stretch factor (proportion of source extent to destination
+* extent: 1:1, 1:2, 1:4, 1:N, N:1, 4:1,or 2:1) and also the
+* delta fraction (see above comment on X_FUNC). This is the ratio of
+* the smaller extent to the larger extent, represented as a fraction
+* multiplied by 65536.
+*
+* returns: the stretch factor (stores the delta fraction in *pfract)
+*/
+
+int
+StretchFactor(int SrcE, int DstE, int *pfract)
+{
+
+
+ if (SrcE == DstE) {
+ if (pfract != NULL) {
+ pfract = 0;
+ }
+
+ return(STRETCH_1_1);
+
+ }
+
+
+ if (SrcE > DstE) {
+ if (pfract != NULL) {
+ *pfract = ( (DstE << 16) / SrcE) & 0xffff;
+ }
+
+ if (SrcE == (DstE * 2)) {
+ return(STRETCH_2_1);
+ } else if (SrcE == (DstE * 4)) {
+ return(STRETCH_4_1);
+ } else {
+ return(STRETCH_N_1);
+ }
+
+ } else {
+
+ /* calculate delta fraction based on smallest / largest */
+ if (pfract != NULL) {
+ *pfract = ( (SrcE << 16) / DstE) & 0xffff;
+ }
+
+ if (DstE == (SrcE * 2)) {
+ return(STRETCH_1_2);
+ } else if (DstE == (SrcE * 4)) {
+ return(STRETCH_1_4);
+ } else {
+ return(STRETCH_1_N);
+ }
+ }
+}
+
+
+/* -------------------------------------------------------------------- */
+
+/*
+* StretchDIB
+*
+*/
+
+void FAR PASCAL
+StretchDIB(
+ LPBITMAPINFOHEADER biDst, // --> BITMAPINFO of destination
+ LPVOID lpvDst, // --> to destination bits
+ int DstX, // Destination origin - x coordinate
+ int DstY, // Destination origin - y coordinate
+ int DstXE, // x extent of the BLT
+ int DstYE, // y extent of the BLT
+ LPBITMAPINFOHEADER biSrc, // --> BITMAPINFO of source
+ LPVOID lpvSrc, // --> to source bits
+ int SrcX, // Source origin - x coordinate
+ int SrcY, // Source origin - y coordinate
+ int SrcXE, // x extent of the BLT
+ int SrcYE // y extent of the BLT
+ )
+{
+
+ int nBits;
+ int SrcWidth, DstWidth;
+ LPBYTE lpDst = (LPBYTE)lpvDst, lpSrc = (LPBYTE)lpvSrc;
+ int x_fract;
+ int x_factor;
+ int y_factor;
+ X_FUNC xfunc;
+
+
+ /*
+ * chek that sizes are not same
+ */
+ /*if(DstXE == SrcXE && DstYE == SrcYE)
+ {
+ return;
+ }*/
+ /*
+ * check that bit depths are same and 8, 16 or 24
+ */
+
+ if ((nBits = biDst->biBitCount) != biSrc->biBitCount) {
+ return;
+ }
+
+ if ( (nBits != 8 ) && (nBits != 16) && (nBits != 24) &&
+ (nBits != 32)) {
+ return;
+ }
+
+ /*
+ * check that extents are not bad
+ */
+ if ( (SrcXE <= 0) || (SrcYE <= 0) || (DstXE <= 0) || (DstYE <= 0)) {
+ return;
+ }
+
+ /*
+ * calculate width of one scan line in bytes, rounded up to
+ * DWORD boundary.
+ */
+ SrcWidth = (((biSrc->biWidth * nBits) + 31) & ~31) / 8;
+ DstWidth = (((biDst->biWidth * nBits) + 31) & ~31) / 8;
+
+ /*
+ * set initial source and dest pointers
+ */
+ lpSrc += (SrcY * SrcWidth) + ((SrcX * nBits) / 8);
+ lpDst += (DstY * DstWidth) + ((DstX * nBits) / 8);
+
+
+ /*
+ * calculate stretch proportions (1:1, 1:2, 1:N, N:1 etc) and
+ * also the fractional stretch factor. (we are not interested in
+ * the y stretch fraction - this is only used in x stretching.
+ */
+
+ y_factor = StretchFactor(SrcYE, DstYE, NULL);
+ x_factor = StretchFactor(SrcXE, DstXE, &x_fract);
+
+ /*
+ * we have special case routines for 1:2 in both dimensions
+ * for 8 and 16 bits
+ */
+ if ((y_factor == x_factor) && (y_factor == STRETCH_1_2)) {
+
+ if (nBits == 8) {
+ //StartCounting();
+ Stretch_1_2_8Bits(lpSrc, lpDst, SrcXE, SrcYE,
+ DstXE, DstYE, SrcWidth, DstWidth,
+ x_fract);
+ //EndCounting("8 bit");
+ return;
+
+ } else if (nBits == 16) {
+ //StartCounting();
+ Stretch_1_2_16Bits(lpSrc, lpDst, SrcXE, SrcYE,
+ DstXE, DstYE, SrcWidth, DstWidth,
+ x_fract);
+ //EndCounting("16 bit");
+ return;
+ }
+ }
+
+
+ /* pick an X stretch function */
+ switch(nBits) {
+
+ case 8:
+ switch(x_factor) {
+ case STRETCH_1_1:
+ xfunc = X_Stretch_1_1_8Bits;
+ break;
+
+ case STRETCH_1_2:
+ xfunc = X_Stretch_1_2_8Bits;
+ break;
+
+ case STRETCH_1_4:
+ xfunc = X_Stretch_1_4_8Bits;
+ break;
+
+ case STRETCH_1_N:
+ xfunc = X_Stretch_1_N_8Bits;
+ break;
+
+ case STRETCH_N_1:
+ case STRETCH_4_1:
+ case STRETCH_2_1:
+ xfunc = X_Stretch_N_1_8Bits;
+ break;
+
+ }
+ break;
+
+ case 16:
+ switch(x_factor) {
+ case STRETCH_1_1:
+ xfunc = X_Stretch_1_1_16Bits;
+ break;
+
+ case STRETCH_1_2:
+ xfunc = X_Stretch_1_2_16Bits;
+ break;
+
+ case STRETCH_1_4:
+ case STRETCH_1_N:
+ xfunc = X_Stretch_1_N_16Bits;
+ break;
+
+ case STRETCH_N_1:
+ case STRETCH_4_1:
+ case STRETCH_2_1:
+ xfunc = X_Stretch_N_1_16Bits;
+ break;
+
+ }
+ break;
+
+ case 24:
+ switch(x_factor) {
+ case STRETCH_1_1:
+ xfunc = X_Stretch_1_1_24Bits;
+ break;
+
+ case STRETCH_1_2:
+ case STRETCH_1_4:
+ case STRETCH_1_N:
+ xfunc = X_Stretch_1_N_24Bits;
+ break;
+
+ case STRETCH_N_1:
+ case STRETCH_4_1:
+ case STRETCH_2_1:
+ xfunc = X_Stretch_N_1_24Bits;
+ break;
+
+ }
+ break;
+
+ case 32:
+ switch(x_factor) {
+ case STRETCH_1_1:
+ xfunc = X_Stretch_1_1_32Bits;
+ break;
+
+ case STRETCH_1_2:
+ case STRETCH_1_4:
+ case STRETCH_1_N:
+ xfunc = X_Stretch_1_N_32Bits;
+ break;
+
+ case STRETCH_N_1:
+ case STRETCH_4_1:
+ case STRETCH_2_1:
+ xfunc = X_Stretch_N_1_32Bits;
+ break;
+
+ }
+ break;
+
+ }
+
+
+ /*
+ * now call appropriate stretching function depending
+ * on the y stretch factor
+ */
+ switch (y_factor) {
+ case STRETCH_1_1:
+ case STRETCH_1_2:
+ case STRETCH_1_4:
+ case STRETCH_1_N:
+ Y_Stretch_1_N(lpSrc, lpDst, SrcXE, SrcYE,
+ DstXE, DstYE, SrcWidth, DstWidth, x_fract, xfunc, nBits);
+ break;
+
+ case STRETCH_N_1:
+ case STRETCH_4_1:
+ case STRETCH_2_1:
+ Y_Stretch_N_1(lpSrc, lpDst, SrcXE, SrcYE,
+ DstXE, DstYE, SrcWidth, DstWidth, x_fract, xfunc);
+ break;
+
+ }
+ return;
+}
+
+
+/* ---- y stretching -------------------------------------------- */
+
+/*
+* call an X_FUNC to copy scanlines from lpSrc to lpDst. Duplicate or
+* omit scanlines to stretch SrcYE to DstYE.
+*/
+
+
+/*
+* Y_Stretch_1_N
+*
+* write DstYE scanlines based on SrcYE scanlines, DstYE > SrcYE
+*
+*/
+
+void
+Y_Stretch_1_N(LPBYTE lpSrc,
+ LPBYTE lpDst,
+ int SrcXE,
+ int SrcYE,
+ int DstXE,
+ int DstYE,
+ int SrcWidth,
+ int DstWidth,
+ int x_fract,
+ X_FUNC x_func,
+ int nBits)
+{
+
+ int ydelta;
+ register int i;
+ LPBYTE lpPrev = NULL;
+
+ ydelta = DstYE -1;
+
+ for (i = 0; i < DstYE; i++) {
+
+ /* have we already stretched this scanline ? */
+ if (lpPrev == NULL) {
+ /* no - copy one scanline */
+ (*x_func)(lpSrc, lpDst, SrcXE, DstXE, x_fract);
+ lpPrev = lpDst;
+ } else {
+ /* yes - this is a duplicate scanline. do
+ * a straight copy of one that has already
+ * been stretched/shrunk
+ */
+ X_CopyScanline(lpPrev, lpDst, DstXE * nBits / 8);
+ }
+
+ /* advance dest pointer */
+ lpDst += DstWidth;
+
+ /* should we advance source pointer this time ? */
+ if ( (ydelta -= SrcYE) < 0) {
+ ydelta += DstYE;
+ lpSrc += SrcWidth;
+ lpPrev = NULL;
+ }
+ }
+}
+
+
+/*
+* Y_Stretch_N_1
+*
+* write DstYE scanlines based on SrcYE scanlines, DstYE < SrcYE
+*
+*/
+void
+Y_Stretch_N_1(LPBYTE lpSrc,
+ LPBYTE lpDst,
+ int SrcXE,
+ int SrcYE,
+ int DstXE,
+ int DstYE,
+ int SrcWidth,
+ int DstWidth,
+ int x_fract,
+ X_FUNC x_func)
+{
+
+ int ydelta;
+ register int i;
+
+ ydelta = SrcYE -1;
+
+ for (i = 0; i < DstYE; i++) {
+
+ /* copy one scanline */
+ (*x_func)(lpSrc, lpDst, SrcXE, DstXE, x_fract);
+
+ /* advance dest pointer */
+ lpDst += DstWidth;
+
+ /* how many times do we advance source pointer this time ? */
+ do {
+ lpSrc += SrcWidth;
+ ydelta -= DstYE;
+ } while (ydelta >= 0);
+
+ ydelta += SrcYE;
+ }
+}
+
+/* ---8-bit X stretching -------------------------------------------------- */
+
+/*
+* X_Stretch_1_N_8Bits
+*
+* copy one scan line, stretching 1:N (DstXE > SrcXE). For 8-bit depth.
+*/
+void
+X_Stretch_1_N_8Bits(LPBYTE lpSrc,
+ LPBYTE lpDst,
+ int SrcXE,
+ int DstXE,
+ int x_fract)
+{
+ int xdelta;
+ register int i;
+
+ xdelta = DstXE -1;
+
+ for (i = 0; i < DstXE; i++) {
+
+ /* copy one byte and advance dest */
+ *lpDst++ = *lpSrc;
+
+ /* should we advance source pointer this time ? */
+ if ( (xdelta -= SrcXE) < 0) {
+ xdelta += DstXE;
+ lpSrc++;
+ }
+ }
+}
+
+
+/*
+* X_Stretch_N_1_8Bits
+*
+* copy one scan line, shrinking N:1 (DstXE < SrcXE). For 8-bit depth.
+*/
+void
+X_Stretch_N_1_8Bits(LPBYTE lpSrc,
+ LPBYTE lpDst,
+ int SrcXE,
+ int DstXE,
+ int x_fract)
+{
+ int xdelta;
+ register int i;
+
+ xdelta = SrcXE -1;
+
+ for (i = 0; i < DstXE; i++) {
+
+ /* copy one byte and advance dest */
+ *lpDst++ = *lpSrc;
+
+ /* how many times do we advance source pointer this time ? */
+ do {
+ lpSrc++;
+ xdelta -= DstXE;
+ } while (xdelta >= 0);
+
+ xdelta += SrcXE;
+ }
+}
+
+/*
+* copy one scanline of count bytes from lpSrc to lpDst. used by 1:1
+* scanline functions for all bit depths
+*/
+void
+X_CopyScanline(LPBYTE lpSrc, LPBYTE lpDst, int count)
+{
+ register int i;
+
+ /*
+ * if the alignment of lpSrc and lpDst is the same, then
+ * we can get them aligned and do a faster copy
+ */
+ if (((DWORD_PTR) lpSrc & 0x3) == ( (DWORD_PTR) lpDst & 0x3)) {
+
+ /* align on WORD boundary */
+ if ( (DWORD_PTR) lpSrc & 0x1) {
+ *lpDst++ = *lpSrc++;
+ count--;
+ }
+
+ /* align on DWORD boundary */
+ if ((DWORD_PTR) lpSrc & 0x2) {
+ * ((LPWORD) lpDst) = *((LPWORD) lpSrc);
+ lpDst += sizeof(WORD);
+ lpSrc += sizeof(WORD);
+ count -= sizeof(WORD);
+ }
+
+ /* copy whole DWORDS */
+ for ( i = (count / 4); i > 0; i--) {
+ *((LPDWORD) lpDst) = *((LPDWORD) lpSrc);
+ lpSrc += sizeof(DWORD);
+ lpDst += sizeof(DWORD);
+ }
+ } else {
+ /* the lpSrc and lpDst pointers are different
+ * alignment, so leave them unaligned and
+ * copy all the whole DWORDs
+ */
+ for (i = (count / 4); i> 0; i--) {
+ *( (DWORD UNALIGNED FAR *) lpDst) =
+ *((DWORD UNALIGNED FAR *) lpSrc);
+ lpSrc += sizeof(DWORD);
+ lpDst += sizeof(DWORD);
+ }
+ }
+
+ /* in either case, copy last (up to 3) bytes. */
+ for ( i = count % 4; i > 0; i--) {
+ *lpDst++ = *lpSrc++;
+ }
+}
+
+/*
+* X_Stretch_1_1_8Bits
+*
+* copy a scanline with no change (1:1)
+*/
+void
+X_Stretch_1_1_8Bits(LPBYTE lpSrc,
+ LPBYTE lpDst,
+ int SrcXE,
+ int DstXE,
+ int x_fract)
+{
+
+ X_CopyScanline(lpSrc, lpDst, DstXE);
+}
+
+
+/*
+* X_Stretch_1_2_8Bits
+*
+* copy a scanline, doubling all the pixels (1:2)
+*/
+void
+X_Stretch_1_2_8Bits(LPBYTE lpSrc,
+ LPBYTE lpDst,
+ int SrcXE,
+ int DstXE,
+ int x_fract)
+{
+ WORD wPix;
+ register int i;
+
+ for (i = 0; i < SrcXE; i++) {
+
+ /* get a pixel and double it */
+ wPix = *lpSrc++;
+ wPix |= (wPix << 8);
+ * ((WORD UNALIGNED *) lpDst) = wPix;
+ lpDst += sizeof(WORD);
+ }
+}
+
+
+/*
+* X_Stretch_1_4_8Bits
+*
+* copy a scanline, quadrupling all the pixels (1:4)
+*/
+void
+X_Stretch_1_4_8Bits(LPBYTE lpSrc,
+ LPBYTE lpDst,
+ int SrcXE,
+ int DstXE,
+ int x_fract)
+{
+ DWORD dwPix;
+ register int i;
+
+ for (i = 0; i < SrcXE; i++) {
+
+ /* get a pixel and make four copies of it */
+ dwPix = *lpSrc++;
+ dwPix |= (dwPix <<8);
+ dwPix |= (dwPix << 16);
+ * ((DWORD UNALIGNED *) lpDst) = dwPix;
+ lpDst += sizeof(DWORD);
+ }
+}
+
+
+/* -- 16-bit X functions -----------------------------------------------*/
+
+/*
+* copy one scan-line of 16 bits with no change (1:1)
+*/
+void
+X_Stretch_1_1_16Bits(LPBYTE lpSrc,
+ LPBYTE lpDst,
+ int SrcXE,
+ int DstXE,
+ int x_fract)
+{
+
+ X_CopyScanline(lpSrc, lpDst, DstXE * sizeof(WORD));
+
+}
+
+
+/*
+* copy one scanline of 16 bpp duplicating each pixel
+*/
+void
+X_Stretch_1_2_16Bits(LPBYTE lpSrc,
+ LPBYTE lpDst,
+ int SrcXE,
+ int DstXE,
+ int x_fract)
+{
+
+ DWORD dwPix;
+ register int i;
+
+ for (i = 0; i < SrcXE; i++) {
+
+ /* get a pixel and double it */
+ dwPix = * ((WORD *)lpSrc);
+ dwPix |= (dwPix << 16);
+ * ((DWORD UNALIGNED *) lpDst) = dwPix;
+
+ lpDst += sizeof(DWORD);
+ lpSrc += sizeof(WORD);
+ }
+
+}
+
+/*
+* copy one scanline of 16 bits, stretching 1:n (dest > source)
+*/
+void
+X_Stretch_1_N_16Bits(LPBYTE lpSrc,
+ LPBYTE lpDst,
+ int SrcXE,
+ int DstXE,
+ int x_fract)
+{
+ int xdelta;
+ register int i;
+
+ xdelta = DstXE -1;
+
+ for (i = 0; i < DstXE; i++) {
+
+ /* copy one pixel and advance dest */
+ *((WORD *) lpDst) = *((WORD *) lpSrc);
+
+ lpDst += sizeof(WORD);
+
+ /* should we advance source pointer this time ? */
+ if ( (xdelta -= SrcXE) < 0) {
+ xdelta += DstXE;
+ lpSrc += sizeof(WORD);
+ }
+ }
+}
+
+/*
+* copy one scanline of 16bits, shrinking n:1 (dest < source)
+*/
+void
+X_Stretch_N_1_16Bits(LPBYTE lpSrc,
+ LPBYTE lpDst,
+ int SrcXE,
+ int DstXE,
+ int x_fract)
+{
+
+ int xdelta;
+ register int i;
+
+ xdelta = SrcXE -1;
+
+ for (i = 0; i < DstXE; i++) {
+
+ /* copy one pixel and advance dest */
+ *((WORD *) lpDst) = *((WORD *)lpSrc);
+
+ lpDst += sizeof(WORD);
+
+ /* how many times do we advance source pointer this time ? */
+ do {
+ lpSrc += sizeof(WORD);
+ xdelta -= DstXE;
+ } while (xdelta >= 0);
+
+ xdelta += SrcXE;
+ }
+
+}
+
+
+/* 24-bits ---------------------------------------------------------*/
+
+/*
+* copy one 24-bpp scanline as is (1:1)
+*/
+void
+X_Stretch_1_1_24Bits(LPBYTE lpSrc,
+ LPBYTE lpDst,
+ int SrcXE,
+ int DstXE,
+ int x_fract)
+{
+ X_CopyScanline(lpSrc, lpDst, DstXE * 3);
+}
+
+/*
+* copy one 24-bpp scanline stretching 1:n (dest > source)
+*/
+void
+X_Stretch_1_N_24Bits(LPBYTE lpSrc,
+ LPBYTE lpDst,
+ int SrcXE,
+ int DstXE,
+ int x_fract)
+{
+
+ int xdelta;
+ register int i;
+
+ xdelta = DstXE -1;
+
+ for (i = 0; i < DstXE; i++) {
+ /* copy first word of pixel and advance dest */
+ *((WORD UNALIGNED *) lpDst) = *((WORD UNALIGNED *) lpSrc);
+
+ lpDst += sizeof(WORD);
+
+ /* copy third byte and advance dest */
+ *lpDst++ = lpSrc[sizeof(WORD)];
+
+ /* should we advance source pointer this time ? */
+ if ( (xdelta -= SrcXE) < 0) {
+ xdelta += DstXE;
+ lpSrc += 3;
+ }
+ }
+}
+
+/*
+* copy one scanline of 24 bits, shrinking n:1 (dest < source)
+*/
+void
+X_Stretch_N_1_24Bits(LPBYTE lpSrc,
+ LPBYTE lpDst,
+ int SrcXE,
+ int DstXE,
+ int x_fract)
+{
+ int xdelta;
+ register int i;
+
+ xdelta = SrcXE -1;
+
+ for (i = 0; i < DstXE; i++) {
+
+ /* copy first word of pixel and advance dest */
+ *((WORD UNALIGNED *) lpDst) = *((WORD UNALIGNED *) lpSrc);
+
+ lpDst += sizeof(WORD);
+
+ /* copy third byte and advance dest */
+ *lpDst++ = lpSrc[sizeof(WORD)];
+
+
+ /* how many times do we advance source pointer this time ? */
+ do {
+ lpSrc += 3;
+ xdelta -= DstXE;
+ } while (xdelta >= 0);
+
+ xdelta += SrcXE;
+ }
+}
+
+
+/* 32-bits ---------------------------------------------------------*/
+
+/*
+* copy one 32-bpp scanline as is (1:1)
+*/
+void
+X_Stretch_1_1_32Bits(LPBYTE lpSrc,
+ LPBYTE lpDst,
+ int SrcXE,
+ int DstXE,
+ int x_fract)
+{
+ X_CopyScanline((BYTE*) lpSrc, (BYTE*) lpDst, DstXE * sizeof( RGBQUAD ) );
+}
+
+/*
+* copy one 32-bpp scanline stretching 1:n (dest > source)
+*/
+void
+X_Stretch_1_N_32Bits(LPBYTE lpSrc0,
+ LPBYTE lpDst0,
+ int SrcXE,
+ int DstXE,
+ int x_fract)
+{
+
+ int xdelta;
+ register int i;
+
+ RGBQUAD *lpSrc=(RGBQUAD *)lpSrc0;
+ RGBQUAD *lpDst=(RGBQUAD *)lpDst0;
+
+
+ xdelta = DstXE -1;
+
+ for (i = 0; i < DstXE; i++)
+ {
+ /* copy first word of pixel and advance dest */
+ *lpDst = *lpSrc;
+ lpDst++;
+
+ /* should we advance source pointer this time ? */
+ if ( (xdelta -= SrcXE) < 0)
+ {
+ xdelta += DstXE;
+ lpSrc++;
+ }
+ }
+}
+
+/*
+* copy one scanline of 32 bits, shrinking n:1 (dest < source)
+*/
+void
+X_Stretch_N_1_32Bits(LPBYTE lpSrc0,
+ LPBYTE lpDst0,
+ int SrcXE,
+ int DstXE,
+ int x_fract)
+{
+ int xdelta;
+ register int i;
+
+ RGBQUAD *lpSrc=(RGBQUAD *)lpSrc0;
+ RGBQUAD *lpDst=(RGBQUAD *)lpDst0;
+
+ xdelta = SrcXE -1;
+
+ for (i = 0; i < DstXE; i++)
+ {
+ *lpDst = *lpSrc;
+ lpDst++;
+
+ /* how many times do we advance source pointer this time ? */
+ do
+ {
+ lpSrc++;
+ xdelta -= DstXE;
+ } while (xdelta >= 0);
+
+ xdelta += SrcXE;
+ }
+}
+
+
+
+
+/* -- special-case 1:2 -------------------------------------------*/
+
+/*
+* stretch 1:2 in both directions, for 8 bits.
+*
+* An experiment was done on x86 to only write every other line during
+* the stretch and when the whole frame was done to use memcpy to fill
+* in the gaps. This is slower than doing the stretch in a single pass.
+*/
+void
+Stretch_1_2_8Bits(LPBYTE lpSrc, LPBYTE lpDst, int SrcXE,int SrcYE, int DstXE,
+ int DstYE, int SrcWidth, int DstWidth, int x_fract)
+{
+
+ int SrcInc, DstInc;
+ register int i, j;
+ WORD wPix;
+ DWORD dwPix4;
+
+ /* amount to advance source by at the end of each scan */
+ SrcInc = SrcWidth - SrcXE;
+
+
+ /* amount to advance dest by at the end of each scan - note
+ * that we write two scans at once, so advance past the next
+ * scan line
+ */
+ DstInc = (DstWidth * 2) - DstXE;
+
+ /*
+ * we would like to copy the pixels DWORD at a time. this means
+ * being aligned. if we are currently aligned on a WORD boundary,
+ * then copy one pixel to get aligned. If we are on a byte
+ * boundary, we can never get aligned, so use the slower loop.
+ */
+ if ( ((DWORD_PTR)lpDst) & 1) {
+
+ /*
+ * dest is byte aligned - so we can never align it
+ * by writing WORDs - use slow loop.
+ */
+ for (i = 0; i < SrcYE; i++) {
+
+ for (j = 0; j < SrcXE; j++) {
+
+ /* get a pixel and double it */
+
+ wPix = *lpSrc++;
+ wPix |= (wPix<<8);
+
+
+ /* write doubled pixel to this scanline */
+
+ *( (WORD UNALIGNED *) lpDst) = wPix;
+
+ /* write double pixel to next scanline */
+ *( (WORD UNALIGNED *) (lpDst + DstWidth)) = wPix;
+
+ lpDst += sizeof(WORD);
+ }
+ lpSrc += SrcInc;
+ lpDst += DstInc;
+ }
+ return;
+ }
+
+ /*
+ * this will be the aligned version. align each scan line
+ */
+ for ( i = 0; i < SrcYE; i++) {
+
+ /* count of pixels remaining */
+ j = SrcXE;
+
+ /* align this scan line */
+ if (((DWORD_PTR)lpDst) & 2) {
+
+ /* word aligned - copy one doubled pixel and we are ok */
+ wPix = *lpSrc++;
+ wPix |= (wPix << 8);
+
+ *( (WORD *) lpDst) = wPix;
+ *( (WORD *) (lpDst + DstWidth)) = wPix;
+ lpDst += sizeof(WORD);
+
+ j -= 1;
+ }
+
+
+ /* now dest is aligned - so loop eating two pixels at a time
+ * until there is at most one left
+ */
+ for ( ; j > 1; j -= 2) {
+
+ /* read two pixels and double them */
+ wPix = * ((WORD UNALIGNED *) lpSrc);
+ lpSrc += sizeof(WORD);
+
+ dwPix4 = (wPix & 0xff) | ((wPix & 0xff) << 8);
+ dwPix4 |= ((wPix & 0xff00) << 8) | ((wPix & 0xff00) << 16);
+ *((DWORD *) lpDst) = dwPix4;
+ *((DWORD *) (lpDst + DstWidth)) = dwPix4;
+
+ lpDst += sizeof(DWORD);
+ }
+
+ /* odd byte remaining ? */
+ if (j > 0) {
+ /* word aligned - copy one doubled pixel and we are ok */
+ wPix = *lpSrc++;
+ wPix |= (wPix << 8);
+
+ *( (WORD *) lpDst) = wPix;
+ *( (WORD *) (lpDst + DstWidth)) = wPix;
+ lpDst += sizeof(WORD);
+
+ j -= 1;
+ }
+ lpSrc += SrcInc;
+ lpDst += DstInc;
+ }
+}
+
+
+
+/* ----------------------------------------------------------------*/
+
+/*
+* stretch 1:2 in both directions, for 16-bits
+*/
+
+void
+Stretch_1_2_16Bits(LPBYTE lpSrc, LPBYTE lpDst, int SrcXE,int SrcYE, int DstXE,
+ int DstYE, int SrcWidth, int DstWidth, int x_fract)
+
+{
+ int SrcInc, DstInc;
+ register int i, j;
+ DWORD dwPix;
+
+ /* amount to advance source by at the end of each scan */
+ SrcInc = SrcWidth - (SrcXE * sizeof(WORD));
+
+
+ /* amount to advance dest by at the end of each scan - note
+ * that we write two scans at once, so advance past the next
+ * scan line
+ */
+ DstInc = (DstWidth * 2) - (DstXE * sizeof(WORD));
+
+ for (i = 0; i < SrcYE; i++) {
+
+ for (j = 0; j < SrcXE; j++) {
+
+ /* get a pixel and double it */
+
+ dwPix = *((WORD *)lpSrc);
+ dwPix |= (dwPix<<16);
+
+ lpSrc += sizeof(WORD);
+
+ /* write doubled pixel to this scanline */
+
+ *( (DWORD UNALIGNED *) lpDst) = dwPix;
+
+ /* write double pixel to next scanline */
+ *( (DWORD UNALIGNED *) (lpDst + DstWidth)) = dwPix;
+
+ lpDst += sizeof(DWORD);
+ }
+ lpSrc += SrcInc;
+ lpDst += DstInc;
+
+ }
+}
diff --git a/plugins/pluginDirectShow/internals/Resizer.h b/plugins/pluginDirectShow/internals/Resizer.h
new file mode 100644
index 0000000..6c76970
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/Resizer.h
@@ -0,0 +1,76 @@
+/* Copyright (C) 2011-2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+/*
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ */
+#ifndef PLUGIN_DSHOW_RESIZER_H
+#define PLUGIN_DSHOW_RESIZER_H
+
+#include "plugin_dshow_config.h"
+
+/*
+* StretchC.C
+*
+* StretchBlt for DIBs
+*
+* C version of stretch.asm: StretchDIB optimised for AVI.
+*
+* NOTES
+* - does not handle mirroring in x or y
+* - does not handle pixel translation
+* - will not work in place.
+*/
+
+
+/* Outline:
+*
+* we select a y-stretching function depending on the ratio (eg 1:N or N:1).
+* it copies scanlines from source to destination, duplicating or omitting
+* scanlines as necessary to fit the destination. It copies each scanline
+* via the X_FUNC function we passed as an argument: this copies one scanline
+* duplicating or omitting pixels to fit the destination: we select an X_FUNC
+* depending on the bit-depth as well as the x-stretching ratio.
+*
+* both x and y stretching functions use the following basic model for deciding
+* when to insert/omit elements:
+*
+* delta = <larger extent> -1;
+*
+* for (number of destination elements) {
+*
+* copy one element
+* advance pointer to larger region
+* delta -= <smaller extent>
+* if (delta < 0) {
+* delta += <larger extent>;
+* advance pointer to smaller region
+* }
+* }
+*/
+
+#include <streams.h>
+
+
+void ResizeRGB( BITMAPINFOHEADER *pbiIn, //Src's BitMapInFoHeader
+ const unsigned char * dibBits, //Src bits
+ BITMAPINFOHEADER *pbiOut,
+ unsigned char *pFrame, //Dst bits
+ int iNewWidth, //new W in pixel
+ int iNewHeight); //new H in pixel
+
+#endif //RESIZER_H
diff --git a/plugins/pluginDirectShow/internals/VideoDisplayName.cxx b/plugins/pluginDirectShow/internals/VideoDisplayName.cxx
new file mode 100644
index 0000000..6b4d0b0
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/VideoDisplayName.cxx
@@ -0,0 +1,37 @@
+/* Copyright (C) 2011-2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#include "internals/VideoDisplayName.h"
+
+VideoDisplayName::VideoDisplayName(std::string name_, std::string descr) : name(name_), description(descr)
+{
+}
+
+std::string VideoDisplayName::getName() const
+{
+ return this->name;
+}
+
+std::string VideoDisplayName::getDescription() const
+{
+ return this->description;
+}
+
+int VideoDisplayName::operator==(const VideoDisplayName &dev) const
+{
+ return this->name == dev.name;
+}
diff --git a/plugins/pluginDirectShow/internals/VideoDisplayName.h b/plugins/pluginDirectShow/internals/VideoDisplayName.h
new file mode 100644
index 0000000..82dc0d0
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/VideoDisplayName.h
@@ -0,0 +1,43 @@
+/* Copyright (C) 2011-2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#ifndef PLUGIN_DSHOW_VIDEODISPLAYNAME_H
+#define PLUGIN_DSHOW_VIDEODISPLAYNAME_H
+
+#include "plugin_dshow_config.h"
+
+#include <string>
+
+class VideoDisplayName
+{
+public:
+ VideoDisplayName() {}
+
+ VideoDisplayName(std::string name, std::string description);
+
+ std::string getName() const;
+
+ std::string getDescription() const;
+
+ int operator==( const VideoDisplayName &dev ) const;
+
+private:
+ std::string name;
+ std::string description;
+};
+
+#endif /* PLUGIN_DSHOW_VIDEODISPLAYNAME_H */
diff --git a/plugins/pluginDirectShow/internals/VideoFrame.h b/plugins/pluginDirectShow/internals/VideoFrame.h
new file mode 100644
index 0000000..2c910a6
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/VideoFrame.h
@@ -0,0 +1,107 @@
+/* Copyright (C) 2011-2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#ifndef PLUGIN_DSHOW_VIDEOFRAME_H
+#define PLUGIN_DSHOW_VIDEOFRAME_H
+
+// Define supported video formats
+typedef enum _VIDEOFORMAT
+{
+ VIDEOFORMAT_NULL = 0, // 0 x 0 : Null
+ VIDEOFORMAT_SQCIF, // 128 x 96 : SQCIF
+ VIDEOFORMAT_QCIF, // 176 x 144 : QCIF
+ VIDEOFORMAT_QVGA, // 320 x 240 : QVGA
+ VIDEOFORMAT_CIF, // 352 x 288 : CIF
+ VIDEOFORMAT_IOS_MEDIUM, // 480 x 360 : IOS_MEDIUM
+ VIDEOFORMAT_VGA, // 640 x 480 : VGA
+ VIDEOFORMAT_4CIF, // 704 x 576 : 4CIF
+ VIDEOFORMAT_SVGA, // 800 x 600 : SVGA
+ VIDEOFORMAT_XGA, // 1024 x 768 : XGA
+ VIDEOFORMAT_SXGA, // 1280 x 1024 : SXGA
+ VIDEOFORMAT_16CIF, // 1408 x 1152 : 16CIF
+} VIDEOFORMAT;
+
+
+// Macro to convert a video format to its size
+#define VIDEOFORMAT_TO_SIZE(format, width, height) \
+ switch(format) \
+ { \
+ case VIDEOFORMAT_SQCIF: width = 128; height = 96; break; \
+ case VIDEOFORMAT_QCIF: width = 176; height = 144; break; \
+ case VIDEOFORMAT_QVGA: width = 320; height = 240; break; \
+ case VIDEOFORMAT_CIF: width = 352; height = 288; break; \
+ case VIDEOFORMAT_IOS_MEDIUM: width = 480; height = 360; break; \
+ case VIDEOFORMAT_VGA: width = 640; height = 480; break; \
+ case VIDEOFORMAT_4CIF: width = 704; height = 576; break; \
+ case VIDEOFORMAT_SVGA: width = 800; height = 600; break; \
+ case VIDEOFORMAT_XGA: width = 1024; height = 768; break; \
+ case VIDEOFORMAT_SXGA: width = 1280; height = 1024; break; \
+ case VIDEOFORMAT_16CIF: width = 1408; height = 1152; break; \
+ case VIDEOFORMAT_NULL: \
+ default: width = 0; height = 0; break; \
+ } \
+
+
+// Macro to get a video format from its size
+#define SIZE_TO_VIDEOFORMAT(width, height, format) \
+ if ((width == 128) && (height = 96)) format = VIDEOFORMAT_SQCIF; \
+ else if ((width == 176) && (height = 144)) format = VIDEOFORMAT_QCIF; \
+ else if ((width == 320) && (height = 240)) format = VIDEOFORMAT_QVGA; \
+ else if ((width == 352) && (height = 288)) format = VIDEOFORMAT_CIF; \
+ else if ((width == 480) && (height = 360)) format = VIDEOFORMAT_IOS_MEDIUM; \
+ else if ((width == 640) && (height = 480)) format = VIDEOFORMAT_VGA; \
+ else if ((width == 704) && (height = 576)) format = VIDEOFORMAT_4CIF; \
+ else if ((width == 800) && (height = 600)) format = VIDEOFORMAT_SVGA; \
+ else if ((width == 1024) && (height = 768)) format = VIDEOFORMAT_XGA; \
+ else if ((width == 1280) && (height = 1024)) format = VIDEOFORMAT_SXGA; \
+ else if ((width == 1408) && (height = 1152)) format = VIDEOFORMAT_16CIF; \
+ else format = VIDEOFORMAT_NULL; \
+
+
+// Constants for consumer and producer Ids
+#define GRABBER_VIDEO_ID 0x1FFFFFFF
+#define REMOTE_VIDEO_ID 0x2FFFFFFF
+
+
+class VideoFrame
+{
+public:
+ VideoFrame() { this->data = NULL; };
+ virtual ~VideoFrame() { if(this->data) { this->data = NULL;} };
+
+ int getWidth() { return this->width; };
+ int getHeight() { return this->height; };
+ int getBitsPerPixel() { return this->bpp; };
+ int getTotalBits () { return this->width * this->height * (this->bpp/8); };
+ void* getData() { return this->data; };
+
+ void setWidth(int width_) { this->width = width_; };
+ void setHeight(int height_) { this->height = height_; };
+ void setBitsPerPixel( int bpp_) { this->bpp = bpp_; };
+ void setData( void* data_) { this->data = data_; };
+
+ VIDEOFORMAT getSize();
+ void setSize(VIDEOFORMAT format);
+
+private:
+ void *data;
+ int width;
+ int height;
+ int bpp;
+};
+
+#endif /* VIDEOFRAME_H */
diff --git a/plugins/pluginDirectShow/internals/VideoGrabberName.cxx b/plugins/pluginDirectShow/internals/VideoGrabberName.cxx
new file mode 100644
index 0000000..4b418cf
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/VideoGrabberName.cxx
@@ -0,0 +1,37 @@
+/* Copyright (C) 2011-2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#include "internals/VideoGrabberName.h"
+
+VideoGrabberName::VideoGrabberName(std::string name_, std::string descr) : name(name_), description(descr)
+{
+}
+
+std::string VideoGrabberName::getName() const
+{
+ return this->name;
+}
+
+std::string VideoGrabberName::getDescription() const
+{
+ return this->description;
+}
+
+int VideoGrabberName::operator==(const VideoGrabberName &dev) const
+{
+ return this->name == dev.name;
+} \ No newline at end of file
diff --git a/plugins/pluginDirectShow/internals/VideoGrabberName.h b/plugins/pluginDirectShow/internals/VideoGrabberName.h
new file mode 100644
index 0000000..0bb45b5
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/VideoGrabberName.h
@@ -0,0 +1,43 @@
+/* Copyright (C) 2011-2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#ifndef PLUGIN_DSHOW_VIDEOGRABBERNAME_H
+#define PLUGIN_DSHOW_VIDEOGRABBERNAME_H
+
+#include "plugin_dshow_config.h"
+
+#include<string>
+
+class VideoGrabberName
+{
+public:
+ VideoGrabberName() {}
+
+ VideoGrabberName(std::string name, std::string description);
+
+ std::string getName() const;
+
+ std::string getDescription() const;
+
+ int operator==( const VideoGrabberName &dev ) const;
+
+private:
+ std::string name;
+ std::string description;
+};
+
+#endif /* PLUGIN_DSHOW_VIDEOGRABBERNAME_H */
diff --git a/plugins/pluginDirectShow/internals/wince/CPropertyBag.cxx b/plugins/pluginDirectShow/internals/wince/CPropertyBag.cxx
new file mode 100644
index 0000000..a6b436a
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/wince/CPropertyBag.cxx
@@ -0,0 +1,108 @@
+#if defined(_WIN32_WCE)
+//
+// Copyright (c) Microsoft Corporation.  All rights reserved.
+//
+//
+// Use of this source code is subject to the terms of the Microsoft end-user
+// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
+// If you did not accept the terms of the EULA, you are not authorized to use
+// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
+// install media.
+//
+#include <windows.h>
+#include <Ocidl.h>
+#include <oleauto.h>
+
+#include "internals/wince/CPropertyBag.h"
+
+CPropertyBag::CPropertyBag() : _refCount(1), pVar(0)
+{
+}
+
+CPropertyBag::~CPropertyBag()
+{
+ VAR_LIST *pTemp = pVar;
+ HRESULT hr = S_OK;
+
+ while(pTemp) {
+ VAR_LIST *pDel = pTemp;
+ VariantClear(&pTemp->var);
+ SysFreeString(pTemp->pBSTRName);
+ pTemp = pTemp->pNext;
+ delete pDel;
+ }
+
+}
+
+HRESULT STDMETHODCALLTYPE
+CPropertyBag::Read(LPCOLESTR pszPropName,
+ VARIANT *_pVar,
+ IErrorLog *pErrorLog)
+{
+ VAR_LIST *pTemp = pVar;
+ HRESULT hr = S_OK;
+
+ while (pTemp) {
+ if (0 == wcscmp(pszPropName, pTemp->pBSTRName)) {
+ hr = VariantCopy(_pVar, &pTemp->var);
+ break;
+ }
+ pTemp = pTemp->pNext;
+ }
+ return hr;
+}
+
+
+HRESULT STDMETHODCALLTYPE
+CPropertyBag::Write(LPCOLESTR pszPropName,
+ VARIANT *_pVar)
+{
+ HRESULT hr = S_OK;
+ VAR_LIST *pTemp = new VAR_LIST();
+ ASSERT(pTemp);
+
+ if ( !pTemp ) {
+ return E_OUTOFMEMORY;
+ }
+
+ VariantInit(&pTemp->var);
+ pTemp->pBSTRName = SysAllocString(pszPropName);
+ pTemp->pNext = pVar;
+ pVar = pTemp;
+ return VariantCopy(&pTemp->var, _pVar);
+}
+
+ULONG STDMETHODCALLTYPE
+CPropertyBag::AddRef()
+{
+ return InterlockedIncrement((LONG *)&_refCount);
+}
+
+ULONG STDMETHODCALLTYPE
+CPropertyBag::Release()
+{
+ ASSERT(_refCount != 0xFFFFFFFF);
+ ULONG ret = InterlockedDecrement((LONG *)&_refCount);
+ if (!ret) {
+ delete this;
+ }
+ return ret;
+}
+
+HRESULT STDMETHODCALLTYPE
+CPropertyBag::QueryInterface(REFIID riid, void** ppv)
+{
+ if (!ppv) {
+ return E_POINTER;
+ }
+ if (riid == IID_IPropertyBag) {
+ *ppv = static_cast<IPropertyBag*>(this);
+ }
+ else {
+ return *ppv = 0, E_NOINTERFACE;
+ }
+
+ return AddRef(), S_OK;
+}
+
+#endif /* _WIN32_WCE */
diff --git a/plugins/pluginDirectShow/internals/wince/CPropertyBag.h b/plugins/pluginDirectShow/internals/wince/CPropertyBag.h
new file mode 100644
index 0000000..20ce779
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/wince/CPropertyBag.h
@@ -0,0 +1,43 @@
+#pragma once
+
+#if defined(_WIN32_WCE)
+
+#include "plugin_dshow_config.h"
+
+struct VAR_LIST
+{
+ VARIANT var;
+ VAR_LIST *pNext;
+ BSTR pBSTRName;
+};
+
+class CPropertyBag : public IPropertyBag
+{
+public:
+ CPropertyBag();
+ ~CPropertyBag();
+
+ HRESULT STDMETHODCALLTYPE
+ Read(
+ LPCOLESTR pszPropName,
+ VARIANT *pVar,
+ IErrorLog *pErrorLog
+ );
+
+
+ HRESULT STDMETHODCALLTYPE
+ Write(
+ LPCOLESTR pszPropName,
+ VARIANT *pVar
+ );
+
+ ULONG STDMETHODCALLTYPE AddRef();
+ ULONG STDMETHODCALLTYPE Release();
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppv);
+
+private:
+ ULONG _refCount;
+ VAR_LIST *pVar;
+};
+
+#endif /* _WIN32_WCE */
diff --git a/plugins/pluginDirectShow/internals/wince/DSISampleGrabberCB.h b/plugins/pluginDirectShow/internals/wince/DSISampleGrabberCB.h
new file mode 100644
index 0000000..89d8909
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/wince/DSISampleGrabberCB.h
@@ -0,0 +1,30 @@
+/* Copyright (C) 2014-2015 Mamadou DIOP
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#pragma once
+
+#if defined(_WIN32_WCE)
+
+#include "plugin_dshow_config.h"
+
+interface DSISampleGrabberCB
+{
+ virtual HRESULT STDMETHODCALLTYPE SampleCB(double SampleTime, IMediaSample *pSample) = 0;
+ virtual HRESULT STDMETHODCALLTYPE BufferCB(double SampleTime, BYTE *pBuffer, long BufferLen) = 0;
+};
+
+#endif /* _WIN32_WCE */ \ No newline at end of file
diff --git a/plugins/pluginDirectShow/internals/wince/DSNullFilter.cxx b/plugins/pluginDirectShow/internals/wince/DSNullFilter.cxx
new file mode 100644
index 0000000..76d713c
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/wince/DSNullFilter.cxx
@@ -0,0 +1,56 @@
+#if defined(_WIN32_WCE)
+
+/* Copyright (C) 2014-2015 Mamadou DIOP
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+
+#include "internals/wince/DSNullFilter.h"
+
+// {7F9F08CF-139F-40b2-A283-01C4EC26A452}
+TDSHOW_DEFINE_GUID(CLSID_DSNullFilter,
+0x7f9f08cf, 0x139f, 0x40b2, 0xa2, 0x83, 0x1, 0xc4, 0xec, 0x26, 0xa4, 0x52);
+
+DSNullFilter::DSNullFilter(LPUNKNOWN punk,HRESULT *phr)
+ : CTransInPlaceFilter(TEXT("NullRenderer"), punk, CLSID_DSNullFilter, phr)
+{
+}
+
+HRESULT DSNullFilter::CheckInputType(const CMediaType *mtIn)
+{
+ CheckPointer(mtIn,E_POINTER);
+
+ if (*mtIn->FormatType() != FORMAT_VideoInfo) {
+ return E_INVALIDARG;
+ }
+
+ if ( *mtIn->Type( ) != MEDIATYPE_Video ) {
+ return E_INVALIDARG;
+ }
+
+ if ( *mtIn->Subtype( ) != MEDIASUBTYPE_RGB24 ) {
+ return E_INVALIDARG;
+ }
+
+ return NOERROR;
+}
+
+HRESULT DSNullFilter::Transform(IMediaSample *pSample)
+{
+ return NOERROR;
+}
+
+#endif /* _WIN32_WCE */
diff --git a/plugins/pluginDirectShow/internals/wince/DSNullFilter.h b/plugins/pluginDirectShow/internals/wince/DSNullFilter.h
new file mode 100644
index 0000000..fc9b76a
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/wince/DSNullFilter.h
@@ -0,0 +1,40 @@
+/* Copyright (C) 2014-2015 Mamadou DIOP
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#pragma once
+
+#if defined(_WIN32_WCE)
+
+#include "plugin_dshow_config.h"
+
+#include <streams.h>
+#include <math.h>
+
+class DSNullFilter : public CTransInPlaceFilter
+{
+public:
+
+ DECLARE_IUNKNOWN;
+
+ HRESULT Transform(IMediaSample *pSample);
+ HRESULT CheckInputType(const CMediaType *mtIn);
+
+ // Constructor
+ DSNullFilter( LPUNKNOWN punk, HRESULT *phr );
+};
+
+#endif /* _WIN32_WCE */
diff --git a/plugins/pluginDirectShow/internals/wince/DSSampleGrabber.cxx b/plugins/pluginDirectShow/internals/wince/DSSampleGrabber.cxx
new file mode 100644
index 0000000..d33d105
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/wince/DSSampleGrabber.cxx
@@ -0,0 +1,197 @@
+#if defined(_WIN32_WCE)
+
+#include <ddraw.h>
+#include <internals/wince/DSSampleGrabber.h>
+#include <initguid.h>
+
+
+// {38589364-71FD-4641-B426-E443DB023568}
+TDSHOW_DEFINE_GUID(CLSID_SampleGrabber,
+0x38589364, 0x71fd, 0x4641, 0xb4, 0x26, 0xe4, 0x43, 0xdb, 0x2, 0x35, 0x68);
+
+#define RGB565_MASK_RED 0xF800
+#define RGB565_MASK_GREEN 0x07E0
+#define RGB565_MASK_BLUE 0x001F
+
+DSSampleGrabber::DSSampleGrabber(TCHAR *tszName, LPUNKNOWN punk, HRESULT *phr)
+:CTransInPlaceFilter (tszName, punk, CLSID_SampleGrabber, phr)
+{
+#define FPS_INPUT 30
+#define FPS_OUTPUT 5
+
+ this->m_rtFrameLength = (10000000)/FPS_OUTPUT;
+
+ this->m_inputFps = FPS_INPUT;
+ this->m_outputFps = FPS_OUTPUT;
+
+ this->m_iFrameNumber = 0;
+ this->m_progress = 0;
+ this->m_bProcessFrame = true;
+
+ this->callback = NULL;
+ this->m_rgb24 = NULL;
+
+ m_cRef = 0;
+}
+
+DSSampleGrabber::~DSSampleGrabber() {
+ this->callback = NULL;
+ if(this->m_rgb24)
+ {
+ delete[]this->m_rgb24;
+ this->m_rgb24 = NULL;
+ }
+}
+
+HRESULT DSSampleGrabber::SetFps(int inputFps, int outputFps)
+{
+ if (inputFps <= 0 || outputFps <= 0) {
+ return E_FAIL;
+ }
+
+ // Stop prcessing
+ this->m_bProcessFrame = false;
+
+ if (inputFps < outputFps) {
+ this->m_inputFps = this->m_outputFps = inputFps;
+ }
+ else {
+ this->m_outputFps = outputFps;
+ this->m_inputFps = inputFps;
+ }
+
+ // Restart processing
+ this->m_iFrameNumber = 0;
+ this->m_progress = 0;
+ this->m_bProcessFrame = true;
+
+ return S_OK;
+}
+
+HRESULT DSSampleGrabber::Transform(IMediaSample *pSample)
+{
+ BYTE *pData = NULL;
+ HRESULT hr = S_OK;
+ HRESULT ret = S_FALSE;
+
+ if (!this->m_bProcessFrame) {
+ return S_FALSE;
+ }
+
+ // Get pointer to the video buffer data
+ if ( FAILED(pSample->GetPointer(&pData)) ) {
+ ret = E_FAIL;
+ goto bail;
+ }
+
+ pSample->SetTime(NULL, NULL);
+
+ // Drop frame?
+ if (this->m_iFrameNumber == 0) {
+ ret = S_OK;
+ }
+ else if (this->m_progress >= this->m_inputFps) {
+ this->m_progress -= this->m_inputFps;
+ ret = S_OK;
+ }
+
+ // Mark frame as accepted
+ if (ret == S_OK) {
+ // Set TRUE on every sample for uncompressed frames
+ pSample->SetSyncPoint(TRUE);
+
+ long Size = pSample->GetSize();
+ if ( this->callback ) {
+ LONGLONG start, end;
+ WORD *rgb565 = (WORD*)pData;
+
+ for(int i = 0, i24 = 0, i565 = 0; i< (Size/2); i++, i24+=3, i565+=1) {
+ BYTE *p24 = (this->m_rgb24+i24);
+ WORD val565 = *(rgb565 + i565);
+
+ // extract RGB
+ p24[2] = (val565 & RGB565_MASK_RED) >> 11;
+ p24[1] = (val565 & RGB565_MASK_GREEN) >> 5;
+ p24[0] = (val565 & RGB565_MASK_BLUE);
+
+ // amplify the image
+ p24[2] <<= 3;
+ p24[1] <<= 2;
+ p24[0] <<= 3;
+ }
+
+ pSample->GetMediaTime(&start, &end);
+ this->callback->BufferCB( (double)start, this->m_rgb24, ((Size >> 1) * 3));
+ }
+ }
+
+ this->m_progress += this->m_outputFps;
+ this->m_iFrameNumber++;
+
+bail:
+ SAFE_DELETE_ARRAY( pData );
+ SAFE_RELEASE(pSample);
+
+ return ret;
+}
+
+HRESULT DSSampleGrabber::CheckInputType(const CMediaType* mtIn)
+{
+ VIDEOINFO *video;
+ if ( !IsEqualGUID( *mtIn->Subtype(), MEDIASUBTYPE_RGB565 ) || !(video=(VIDEOINFO *)mtIn->Format()) ) {
+ return E_FAIL;
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP DSSampleGrabber::SetCallback( DSISampleGrabberCB* callback_ )
+{
+ if (!callback_) {
+ return E_FAIL;
+ }
+
+ this->callback = callback_;
+ return S_OK;
+}
+
+HRESULT DSSampleGrabber::SetSize(int width, int height)
+{
+ ZeroMemory(&this->mt, sizeof(CMediaType));
+
+ VIDEOINFO *pvi = (VIDEOINFO *)this->mt.AllocFormatBuffer(sizeof(VIDEOINFO));
+ if (NULL == pvi)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ ZeroMemory(pvi, sizeof(VIDEOINFO));
+
+ pvi->bmiHeader.biCompression = BI_RGB;
+ pvi->bmiHeader.biBitCount = 24;
+ pvi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ pvi->bmiHeader.biWidth = width;
+ pvi->bmiHeader.biHeight = height;
+ pvi->bmiHeader.biPlanes = 1;
+ pvi->bmiHeader.biSizeImage = GetBitmapSize(&pvi->bmiHeader);
+ pvi->bmiHeader.biClrImportant = 0;
+
+ // Frame rate
+ pvi->AvgTimePerFrame = 10000000/this->m_outputFps;
+
+ SetRectEmpty(&(pvi->rcSource)); // we want the whole image area rendered.
+ SetRectEmpty(&(pvi->rcTarget)); // no particular destination rectangle
+
+ this->mt.SetType(&MEDIATYPE_Video);
+ this->mt.SetFormatType(&FORMAT_VideoInfo);
+ this->mt.SetTemporalCompression(FALSE);
+
+ this->mt.SetSubtype(&MEDIASUBTYPE_RGB24);
+ this->mt.SetSampleSize(pvi->bmiHeader.biSizeImage);
+
+ this->m_rgb24 = new BYTE[pvi->bmiHeader.biSizeImage];
+
+ return S_OK;
+}
+
+#endif /* _WIN32_WCE */
diff --git a/plugins/pluginDirectShow/internals/wince/DSSampleGrabber.h b/plugins/pluginDirectShow/internals/wince/DSSampleGrabber.h
new file mode 100644
index 0000000..39ee5c6
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/wince/DSSampleGrabber.h
@@ -0,0 +1,73 @@
+/* Copyright (C) 2014-2015 Mamadou DIOP
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+
+#pragma once
+
+#if defined(_WIN32_WCE)
+
+#include "plugin_dshow_config.h"
+
+#include <streams.h>
+#include <math.h>
+
+#include <internals/DSUtils.h>
+#include <internals/wince/DSISampleGrabberCB.h>
+#include "DSSampleGrabberUtils.h"
+
+class DSSampleGrabber : public CTransInPlaceFilter
+{
+public:
+ // instantiation
+ DSSampleGrabber( TCHAR *tszName, LPUNKNOWN punk, HRESULT *phr );
+ ~DSSampleGrabber(void);
+
+public:
+ HRESULT Transform(IMediaSample *pSample);
+ HRESULT CheckInputType(const CMediaType* mtIn);
+
+ HRESULT SetFps(int inputFps, int outputFps);
+
+ // DECLARE_IUNKNOWN;
+ STDMETHODIMP QueryInterface(REFIID riid, void **ppv) {
+ return GetOwner()->QueryInterface(riid,ppv);
+ };
+ STDMETHODIMP_(ULONG) AddRef() {
+ return InterlockedIncrement(&m_cRef);
+ };
+ STDMETHODIMP_(ULONG) Release() {
+ return GetOwner()->Release();
+ };
+
+ STDMETHODIMP SetCallback(DSISampleGrabberCB* callback_);
+ HRESULT SetSize(int width, int height);
+
+ inline AM_MEDIA_TYPE GetMediaType() { return (AM_MEDIA_TYPE)this->mt; }
+
+private:
+ int m_progress;
+ int m_inputFps, m_outputFps;
+ bool m_bProcessFrame;
+ REFERENCE_TIME m_rtFrameLength; // UNITS/fps
+ LONGLONG m_iFrameNumber;
+
+ DSISampleGrabberCB* callback;
+ CMediaType mt;
+ BYTE *m_rgb24;
+};
+
+#endif /* _WIN32_WCE */
diff --git a/plugins/pluginDirectShow/internals/wince/DSSampleGrabberUtils.h b/plugins/pluginDirectShow/internals/wince/DSSampleGrabberUtils.h
new file mode 100644
index 0000000..01e1728
--- /dev/null
+++ b/plugins/pluginDirectShow/internals/wince/DSSampleGrabberUtils.h
@@ -0,0 +1,38 @@
+/* Copyright (C) 2014-2015 Mamadou DIOP
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#pragma once
+
+#if defined(_WIN32_WCE)
+
+// callback definition
+typedef void (CALLBACK *MANAGEDCALLBACKPROC)(BYTE* pdata, long len);
+
+// ISampleGrabber interface definition
+
+// {04951BFF-696A-4ade-828D-42A5F1EDB631}
+DEFINE_GUID(IID_ISampleGrabber,
+ 0x4951bff, 0x696a, 0x4ade, 0x82, 0x8d, 0x42, 0xa5, 0xf1, 0xed, 0xb6, 0x31);
+
+DECLARE_INTERFACE_(ISampleGrabber, IUnknown) {
+ STDMETHOD(SetCallback)(MANAGEDCALLBACKPROC callback) PURE;};
+
+ // {D11DFE19-8864-4a60-B26C-552F9AA472E1}
+DEFINE_GUID(CLSID_NullRenderer,
+ 0xd11dfe19, 0x8864, 0x4a60, 0xb2, 0x6c, 0x55, 0x2f, 0x9a, 0xa4, 0x72, 0xe1);
+
+#endif /* _WIN32_WCE */
diff --git a/plugins/pluginDirectShow/pluginDirectShow.vcproj b/plugins/pluginDirectShow/pluginDirectShow.vcproj
new file mode 100644
index 0000000..38642ad
--- /dev/null
+++ b/plugins/pluginDirectShow/pluginDirectShow.vcproj
@@ -0,0 +1,379 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="pluginDirectShow"
+ ProjectGUID="{6A69773C-0C70-4BD4-8362-C274CAFD58F2}"
+ RootNamespace="pluginDirectShow"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=".;..\..\thirdparties\win32\include;..\..\thirdparties\win32\include\directshow;..\..\tinySAK\src;..\..\tinyMEDIA\include;..\..\tinySDP\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;PLUGIN_DSHOW_EXPORTS;_WIN32_WINNT=0x0501"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="..\..\thirdparties\win32\lib\directshow\strmbasd.lib dmoguids.lib strmiids.lib uuid.lib Winmm.lib $(OutDir)\tinySAK.lib $(OutDir)\tinyMEDIA.lib"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="3"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories=".;..\..\thirdparties\win32\include;..\..\thirdparties\win32\include\directshow;..\..\tinySAK\src;..\..\tinyMEDIA\include;..\..\tinySDP\include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;PLUGIN_DSHOW_EXPORTS;_WIN32_WINNT=0x0501"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="..\..\thirdparties\win32\lib\directshow\strmbase.lib dmoguids.lib strmiids.lib uuid.lib Winmm.lib $(OutDir)\tinySAK.lib $(OutDir)\tinyMEDIA.lib"
+ LinkIncremental="1"
+ GenerateDebugInformation="false"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\dllmain_dshow.cxx"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_screencast_dshow_producer.cxx"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_video_dshow_consumer.cxx"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_video_dshow_producer.cxx"
+ >
+ </File>
+ <Filter
+ Name="internals"
+ >
+ <File
+ RelativePath=".\internals\DSCaptureFormat.cxx"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\DSCaptureGraph.cxx"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\DSCaptureUtils.cxx"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\DSDibHelper.cxx"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\DSDisplay.cxx"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\DSDisplayGraph.cxx"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\DSDisplayOverlay.cxx"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\DSDisplayOverlay.VMR.cxx"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\DSDisplayOverlay.VMR9.cxx"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\DSFrameRateFilter.cxx"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\DSGrabber.cxx"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\DSOutputFilter.cxx"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\DSOutputStream.cxx"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\DSPushSourceDesktop.cxx"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\DSScreenCastGraph.cxx"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\DSUtils.cxx"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\Resizer.cxx"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\VideoDisplayName.cxx"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\VideoGrabberName.cxx"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\plugin_dshow_config.h"
+ >
+ </File>
+ <Filter
+ Name="internals"
+ >
+ <File
+ RelativePath=".\internals\DSBaseCaptureGraph.h"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\DSBufferWriter.h"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\DSCaptureFormat.h"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\DSCaptureGraph.h"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\DSCaptureUtils.h"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\DSDibHelper.h"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\DSDisplay.h"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\DSDisplayGraph.h"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\DSDisplayOverlay.h"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\DSFrameRateFilter.h"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\DSGrabber.h"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\DSOutputFilter.h"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\DSOutputStream.h"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\DSPushSource.h"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\DSScreenCastGraph.h"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\DSUtils.h"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\Resizer.h"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\VideoDisplayName.h"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\VideoFrame.h"
+ >
+ </File>
+ <File
+ RelativePath=".\internals\VideoGrabberName.h"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ >
+ <File
+ RelativePath=".\version.rc"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/plugins/pluginDirectShow/plugin_dshow_config.h b/plugins/pluginDirectShow/plugin_dshow_config.h
new file mode 100644
index 0000000..f58e4b2
--- /dev/null
+++ b/plugins/pluginDirectShow/plugin_dshow_config.h
@@ -0,0 +1,103 @@
+/* Copyright (C) 2011-2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+
+#ifndef PLUGIN_DSHOW_CONFIG_H
+#define PLUGIN_DSHOW_CONFIG_H
+
+#ifdef __SYMBIAN32__
+#undef _WIN32 /* Because of WINSCW */
+#endif
+
+// Windows (XP/Vista/7/CE and Windows Mobile) macro definition
+#if defined(WIN32)|| defined(_WIN32) || defined(_WIN32_WCE)
+# define PLUGIN_DSHOW_UNDER_WINDOWS 1
+# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP || WINAPI_FAMILY == WINAPI_FAMILY_APP)
+# define PLUGIN_DSHOW_UNDER_WINDOWS_RT 1
+# endif
+#endif
+
+#if (PLUGIN_DSHOW_UNDER_WINDOWS || defined(__SYMBIAN32__)) && defined(PLUGIN_DSHOW_EXPORTS)
+# define PLUGIN_DSHOW_API __declspec(dllexport)
+# define PLUGIN_DSHOW_GEXTERN extern __declspec(dllexport)
+#elif (PLUGIN_DSHOW_UNDER_WINDOWS || defined(__SYMBIAN32__)) && !defined(PLUGIN_DSHOW_IMPORTS_IGNORE)
+# define PLUGIN_DSHOW_API __declspec(dllimport)
+# define PLUGIN_DSHOW_GEXTERN __declspec(dllimport)
+#else
+# define PLUGIN_DSHOW_API
+# define PLUGIN_DSHOW_GEXTERN extern
+#endif
+
+/* Guards against C++ name mangling
+*/
+#ifdef __cplusplus
+# define PLUGIN_DSHOW_BEGIN_DECLS extern "C" {
+# define PLUGIN_DSHOW_END_DECLS }
+#else
+# define PLUGIN_DSHOW_BEGIN_DECLS
+# define PLUGIN_DSHOW_END_DECLS
+#endif
+
+/* Disable some well-known warnings
+*/
+#ifdef _MSC_VER
+# pragma warning (disable:4995 4996)
+# define _CRT_SECURE_NO_WARNINGS
+#endif
+
+/* Detecting C99 compilers
+ */
+#if (__STDC_VERSION__ == 199901L) && !defined(__C99__)
+# define __C99__
+#endif
+
+#if PLUGIN_DSHOW_UNDER_WINDOWS
+#include <windows.h>
+#endif
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <memory.h>
+#include <tchar.h>
+#ifdef __SYMBIAN32__
+#include <stdlib.h>
+#endif
+
+#if HAVE_CONFIG_H
+ #include <config.h>
+#endif
+
+#if !defined(TDSHOW_DEFINE_GUID) && !defined(_WIN32_WCE)
+#define TDSHOW_DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+ EXTERN_C const GUID DECLSPEC_SELECTANY name \
+ = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
+#elif !defined(TDSHOW_DEFINE_GUID) && defined(_WIN32_WCE)
+#define TDSHOW_DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+ EXTERN_C const GUID __declspec(selectany) name \
+ = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
+#endif
+
+#if 1 // workaround for "Cannot open include file: 'dxtrans.h': No such file or directory"
+#pragma include_alias( "dxtrans.h", "qedit.h" )
+#define __IDxtCompositor_INTERFACE_DEFINED__
+#define __IDxtAlphaSetter_INTERFACE_DEFINED__
+#define __IDxtJpeg_INTERFACE_DEFINED__
+#define __IDxtKey_INTERFACE_DEFINED__
+#endif
+
+#endif // PLUGIN_DSHOW_CONFIG_H
diff --git a/plugins/pluginDirectShow/plugin_screencast_dshow_producer.cxx b/plugins/pluginDirectShow/plugin_screencast_dshow_producer.cxx
new file mode 100644
index 0000000..af09c4e
--- /dev/null
+++ b/plugins/pluginDirectShow/plugin_screencast_dshow_producer.cxx
@@ -0,0 +1,273 @@
+/* Copyright (C) 2014 Mamadou DIOP
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#include "internals/DSGrabber.h"
+#include "internals/DSDisplay.h"
+#include "internals/DSUtils.h"
+
+#include "tinymedia/tmedia_producer.h"
+
+#include "tsk_string.h"
+#include "tsk_debug.h"
+
+#define DSPRODUCER(self) ((plugin_screencast_dshow_producer_t*)(self))
+
+typedef struct plugin_screencast_dshow_producer_s
+{
+ TMEDIA_DECLARE_PRODUCER;
+
+ DSGrabber* grabber;
+ INT64 previewHwnd;
+
+ tsk_bool_t started;
+ tsk_bool_t mute;
+ tsk_bool_t create_on_ui_thread;
+}
+plugin_screencast_dshow_producer_t;
+
+// Producer callback (From DirectShow Grabber to our plugin)
+static int plugin_video_dshow_plugin_cb(const void* callback_data, const void* buffer, tsk_size_t size)
+{
+ const plugin_screencast_dshow_producer_t* producer = (const plugin_screencast_dshow_producer_t*)callback_data;
+
+ if (producer && TMEDIA_PRODUCER(producer)->enc_cb.callback) {
+ TMEDIA_PRODUCER(producer)->enc_cb.callback(TMEDIA_PRODUCER(producer)->enc_cb.callback_data, buffer, size);
+ }
+
+ return 0;
+}
+
+
+/* ============ Media Producer Interface ================= */
+static int plugin_screencast_dshow_producer_set(tmedia_producer_t *self, const tmedia_param_t* param)
+{
+ int ret = 0;
+ plugin_screencast_dshow_producer_t* producer = (plugin_screencast_dshow_producer_t*)self;
+
+ if(!producer || !param){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if(param->value_type == tmedia_pvt_int64){
+ if(tsk_striequals(param->key, "local-hwnd")){
+ DSPRODUCER(producer)->previewHwnd = (INT64)*((int64_t*)param->value);
+ if(DSPRODUCER(producer)->grabber && DSPRODUCER(self)->grabber->preview){
+ DSPRODUCER(producer)->grabber->preview->attach(DSPRODUCER(producer)->previewHwnd);
+ }
+ }
+ }
+ else if(param->value_type == tmedia_pvt_int32){
+ if(tsk_striequals(param->key, "mute")){
+ producer->mute = (TSK_TO_INT32((uint8_t*)param->value) != 0);
+ if(producer->started){
+ if(producer->mute){
+ producer->grabber->pause();
+ }
+ else{
+ producer->grabber->start();
+ }
+ }
+ }
+ else if(tsk_striequals(param->key, "create-on-current-thead")){
+ producer->create_on_ui_thread = *((int32_t*)param->value) ? tsk_false : tsk_true;
+ }
+ else if(tsk_striequals(param->key, "plugin-firefox")){
+ TSK_DEBUG_INFO("'plugin-firefox' ignored for screencast");
+ }
+ }
+
+ return ret;
+}
+
+static int plugin_screencast_dshow_producer_prepare(tmedia_producer_t* self, const tmedia_codec_t* codec)
+{
+ plugin_screencast_dshow_producer_t* producer = (plugin_screencast_dshow_producer_t*)self;
+
+ if(!producer || !codec && codec->plugin){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ TMEDIA_PRODUCER(producer)->video.fps = TMEDIA_CODEC_VIDEO(codec)->out.fps;
+ TMEDIA_PRODUCER(producer)->video.width = TMEDIA_CODEC_VIDEO(codec)->out.width;
+ TMEDIA_PRODUCER(producer)->video.height = TMEDIA_CODEC_VIDEO(codec)->out.height;
+
+ return 0;
+}
+
+static int plugin_screencast_dshow_producer_start(tmedia_producer_t* self)
+{
+ plugin_screencast_dshow_producer_t* producer = (plugin_screencast_dshow_producer_t*)self;
+ HRESULT hr = S_OK;
+
+ if (!producer) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if (producer->started) {
+ return 0;
+ }
+
+ // create grabber on ALWAYS current thread
+ if (!producer->grabber) {
+ static BOOL __isDisplayFalse = FALSE;
+ static BOOL __isScreenCastTrue = TRUE;
+ if(producer->create_on_ui_thread) createOnUIThead(reinterpret_cast<HWND>((void*)DSPRODUCER(producer)->previewHwnd), (void**)&producer->grabber, __isDisplayFalse, __isScreenCastTrue);
+ else createOnCurrentThead(reinterpret_cast<HWND>((void*)DSPRODUCER(producer)->previewHwnd), (void**)&producer->grabber, __isDisplayFalse, __isScreenCastTrue);
+ if (!producer->grabber) {
+ TSK_DEBUG_ERROR("Failed to create grabber");
+ return -2;
+ }
+ }
+
+ // set parameters
+ producer->grabber->setCaptureParameters((int)TMEDIA_PRODUCER(producer)->video.width, (int)TMEDIA_PRODUCER(producer)->video.height, TMEDIA_PRODUCER(producer)->video.fps);
+
+ // set callback function
+ producer->grabber->setCallback(plugin_video_dshow_plugin_cb, producer);
+
+ // attach preview
+ if (producer->grabber->preview) {
+ if (producer->previewHwnd) {
+ producer->grabber->preview->attach(producer->previewHwnd);
+ }
+ producer->grabber->preview->setSize((int)TMEDIA_PRODUCER(producer)->video.width, (int)TMEDIA_PRODUCER(producer)->video.height);
+ }
+
+ // start grabber
+ if (!producer->mute) {
+ producer->grabber->start();
+ }
+
+ producer->started = tsk_true;
+
+ return 0;
+}
+
+static int plugin_screencast_dshow_producer_pause(tmedia_producer_t* self)
+{
+ plugin_screencast_dshow_producer_t* producer = (plugin_screencast_dshow_producer_t*)self;
+
+ if(!producer){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if(!producer->grabber){
+ TSK_DEBUG_ERROR("Invalid internal grabber");
+ return -2;
+ }
+
+ producer->grabber->pause();
+
+ return 0;
+}
+
+static int plugin_screencast_dshow_producer_stop(tmedia_producer_t* self)
+{
+ plugin_screencast_dshow_producer_t* producer = (plugin_screencast_dshow_producer_t*)self;
+
+ if(!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if(!producer->started){
+ return 0;
+ }
+
+ if(!producer->grabber){
+ TSK_DEBUG_ERROR("Invalid internal grabber");
+ return -2;
+ }
+
+ producer->grabber->stop();
+ producer->started = tsk_false;
+
+ return 0;
+}
+
+
+//
+// WaveAPI producer object definition
+//
+/* constructor */
+static tsk_object_t* plugin_screencast_dshow_producer_ctor(tsk_object_t * self, va_list * app)
+{
+ CoInitializeEx(NULL, COINIT_MULTITHREADED);
+
+ plugin_screencast_dshow_producer_t *producer = (plugin_screencast_dshow_producer_t *)self;
+ if(producer){
+ /* init base */
+ tmedia_producer_init(TMEDIA_PRODUCER(producer));
+ TMEDIA_PRODUCER(producer)->video.chroma = tmedia_chroma_bgr24; // RGB24 on x86 (little endians) stored as BGR24
+ /* init self with default values*/
+ producer->create_on_ui_thread = tsk_true;
+ TMEDIA_PRODUCER(producer)->video.fps = 15;
+ TMEDIA_PRODUCER(producer)->video.width = 352;
+ TMEDIA_PRODUCER(producer)->video.height = 288;
+ }
+ return self;
+}
+/* destructor */
+static tsk_object_t* plugin_screencast_dshow_producer_dtor(tsk_object_t * self)
+{
+ plugin_screencast_dshow_producer_t *producer = (plugin_screencast_dshow_producer_t *)self;
+ if(producer){
+ /* stop */
+ if(producer->started){
+ plugin_screencast_dshow_producer_stop((tmedia_producer_t*)self);
+ }
+
+ /* for safety */
+ if(producer->grabber){
+ producer->grabber->setCallback(tsk_null, tsk_null);
+ }
+
+ /* deinit base */
+ tmedia_producer_deinit(TMEDIA_PRODUCER(producer));
+ /* deinit self */
+ SAFE_DELETE_PTR(producer->grabber);
+ }
+
+ return self;
+}
+/* object definition */
+static const tsk_object_def_t plugin_screencast_dshow_producer_def_s =
+{
+ sizeof(plugin_screencast_dshow_producer_t),
+ plugin_screencast_dshow_producer_ctor,
+ plugin_screencast_dshow_producer_dtor,
+ tsk_null,
+};
+/* plugin definition*/
+static const tmedia_producer_plugin_def_t plugin_screencast_dshow_producer_plugin_def_s =
+{
+ &plugin_screencast_dshow_producer_def_s,
+
+ tmedia_bfcp_video,
+ "Microsoft DirectShow producer (ScrenCast)",
+
+ plugin_screencast_dshow_producer_set,
+ plugin_screencast_dshow_producer_prepare,
+ plugin_screencast_dshow_producer_start,
+ plugin_screencast_dshow_producer_pause,
+ plugin_screencast_dshow_producer_stop
+};
+const tmedia_producer_plugin_def_t *plugin_screencast_dshow_producer_plugin_def_t = &plugin_screencast_dshow_producer_plugin_def_s;
diff --git a/plugins/pluginDirectShow/plugin_video_dshow_consumer.cxx b/plugins/pluginDirectShow/plugin_video_dshow_consumer.cxx
new file mode 100644
index 0000000..dfd7e72
--- /dev/null
+++ b/plugins/pluginDirectShow/plugin_video_dshow_consumer.cxx
@@ -0,0 +1,1319 @@
+/* Copyright (C) 2011-2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#include "internals/DSDisplay.h"
+#include "internals/DSUtils.h"
+
+#include "tinymedia/tmedia_consumer.h"
+
+#include "tsk_safeobj.h"
+#include "tsk_string.h"
+#include "tsk_debug.h"
+
+
+#define DSCONSUMER(self) ((plugin_video_dshow_consumer_t*)(self))
+
+// Whether to use Direct3D device for direct rendering or DirectShow graph and custom source
+// Using DirectShow (DS) introduce delay when the input fps is different than the one in the custom src.
+// It's very hard to have someting accurate when using DS because the input FPS change depending on the congestion control. D3D is the best choice as frames are displayed as they arrive
+#if !defined(PLUGIN_DS_CV_USE_D3D9) && !defined(_WIN32_WCE)
+# define PLUGIN_DS_CV_USE_D3D9 1
+#endif
+
+/******* ********/
+
+#if PLUGIN_DS_CV_USE_D3D9
+
+#include <d3d9.h>
+#include <dxva2api.h>
+
+#ifdef _MSC_VER
+#pragma comment(lib, "d3d9")
+#endif
+
+const DWORD NUM_BACK_BUFFERS = 2;
+
+#undef SafeRelease
+#define SafeRelease(ppT) \
+{ \
+ if (*ppT) \
+ { \
+ (*ppT)->Release(); \
+ *ppT = NULL; \
+ } \
+}
+
+#undef CHECK_HR
+// In CHECK_HR(x) When (x) is a function it will be executed twice when used in "TSK_DEBUG_ERROR(x)" and "If(x)"
+#define CHECK_HR(x) { HRESULT __hr__ = (x); if (FAILED(__hr__)) { TSK_DEBUG_ERROR("Operation Failed (%08x)", __hr__); goto bail; } }
+
+typedef struct _DSRatio
+ {
+ DWORD Numerator;
+ DWORD Denominator;
+ } DSRatio;
+
+static HRESULT CreateDeviceD3D9(
+ HWND hWnd,
+ IDirect3DDevice9** ppDevice,
+ IDirect3D9 **ppD3D,
+ D3DPRESENT_PARAMETERS &d3dpp
+ );
+static HRESULT TestCooperativeLevel(
+ struct plugin_video_dshow_consumer_s *pSelf
+ );
+static HRESULT CreateSwapChain(
+ HWND hWnd,
+ UINT32 nFrameWidth,
+ UINT32 nFrameHeight,
+ IDirect3DDevice9* pDevice,
+ IDirect3DSwapChain9 **ppSwapChain);
+
+static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+static inline HWND Window(struct plugin_video_dshow_consumer_s *pSelf);
+static inline LONG Width(const RECT& r);
+static inline LONG Height(const RECT& r);
+static inline RECT CorrectAspectRatio(const RECT& src, const DSRatio& srcPAR);
+static inline RECT LetterBoxRect(const RECT& rcSrc, const RECT& rcDst);
+static inline HRESULT UpdateDestinationRect(struct plugin_video_dshow_consumer_s *pSelf, BOOL bForce = FALSE);
+static HRESULT ResetDevice(struct plugin_video_dshow_consumer_s *pSelf, BOOL bUpdateDestinationRect = FALSE);
+static HRESULT SetFullscreen(struct plugin_video_dshow_consumer_s *pSelf, BOOL bFullScreen);
+static HWND CreateFullScreenWindow(struct plugin_video_dshow_consumer_s *pSelf);
+static HRESULT HookWindow(struct plugin_video_dshow_consumer_s *pSelf, HWND hWnd);
+static HRESULT UnhookWindow(struct plugin_video_dshow_consumer_s *pSelf);
+
+
+typedef struct plugin_video_dshow_consumer_s
+{
+ TMEDIA_DECLARE_CONSUMER;
+
+ BOOL bStarted, bPrepared, bPaused, bFullScreen, bWindowHooked;
+ BOOL bPluginFireFox, bPluginWebRTC4All;
+ HWND hWindow;
+ WNDPROC wndProc;
+ HWND hWindowFullScreen;
+ RECT rcWindow;
+ RECT rcDest;
+ DSRatio pixelAR;
+
+ UINT32 nNegWidth;
+ UINT32 nNegHeight;
+ UINT32 nNegFps;
+
+ D3DLOCKED_RECT rcLock;
+ IDirect3DDevice9* pDevice;
+ IDirect3D9 *pD3D;
+ IDirect3DSwapChain9 *pSwapChain;
+ D3DPRESENT_PARAMETERS d3dpp;
+
+ TSK_DECLARE_SAFEOBJ;
+}
+plugin_video_dshow_consumer_t;
+
+static int _plugin_video_dshow_consumer_unprepare(plugin_video_dshow_consumer_t* pSelf);
+
+/* ============ Media Consumer Interface ================= */
+static int plugin_video_dshow_consumer_set(tmedia_consumer_t *self, const tmedia_param_t* param)
+{
+ int ret = 0;
+ HRESULT hr = S_OK;
+ plugin_video_dshow_consumer_t* pSelf = (plugin_video_dshow_consumer_t*)self;
+
+ if(!self || !param)
+ {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ CHECK_HR(hr = E_POINTER);
+ }
+
+ if(param->value_type == tmedia_pvt_int64)
+ {
+ if(tsk_striequals(param->key, "remote-hwnd"))
+ {
+ HWND hWnd = reinterpret_cast<HWND>((INT64)*((int64_t*)param->value));
+ if(hWnd != pSelf->hWindow)
+ {
+ tsk_safeobj_lock(pSelf); // block consumer thread
+ pSelf->hWindow = hWnd;
+ if(pSelf->bPrepared)
+ {
+ hr = ResetDevice(pSelf);
+ }
+ tsk_safeobj_unlock(pSelf); // unblock consumer thread
+ }
+ }
+ }
+ else if(param->value_type == tmedia_pvt_int32)
+ {
+ if(tsk_striequals(param->key, "fullscreen"))
+ {
+ BOOL bFullScreen = !!*((int32_t*)param->value);
+ TSK_DEBUG_INFO("[MF video consumer] Full Screen = %d", bFullScreen);
+ CHECK_HR(hr = SetFullscreen(pSelf, bFullScreen));
+ }
+ else if(tsk_striequals(param->key, "create-on-current-thead"))
+ {
+ // DSCONSUMER(self)->create_on_ui_thread = *((int32_t*)param->value) ? tsk_false : tsk_true;
+ }
+ else if(tsk_striequals(param->key, "plugin-firefox"))
+ {
+ pSelf->bPluginFireFox = (*((int32_t*)param->value) != 0);
+ }
+ else if(tsk_striequals(param->key, "plugin-webrtc4all"))
+ {
+ pSelf->bPluginWebRTC4All = (*((int32_t*)param->value) != 0);
+ }
+ }
+
+ CHECK_HR(hr);
+
+bail:
+ return SUCCEEDED(hr) ? 0 : -1;
+}
+
+
+static int plugin_video_dshow_consumer_prepare(tmedia_consumer_t* self, const tmedia_codec_t* codec)
+{
+ plugin_video_dshow_consumer_t* pSelf = (plugin_video_dshow_consumer_t*)self;
+
+ if(!pSelf || !codec && codec->plugin){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if(pSelf->bPrepared){
+ TSK_DEBUG_WARN("D3D9 video consumer already prepared");
+ return -1;
+ }
+
+ HRESULT hr = S_OK;
+ HWND hWnd = Window(pSelf);
+
+ TMEDIA_CONSUMER(pSelf)->video.fps = TMEDIA_CODEC_VIDEO(codec)->in.fps;
+ TMEDIA_CONSUMER(pSelf)->video.in.width = TMEDIA_CODEC_VIDEO(codec)->in.width;
+ TMEDIA_CONSUMER(pSelf)->video.in.height = TMEDIA_CODEC_VIDEO(codec)->in.height;
+
+ if(!TMEDIA_CONSUMER(pSelf)->video.display.width){
+ TMEDIA_CONSUMER(pSelf)->video.display.width = TMEDIA_CONSUMER(pSelf)->video.in.width;
+ }
+ if(!TMEDIA_CONSUMER(pSelf)->video.display.height){
+ TMEDIA_CONSUMER(pSelf)->video.display.height = TMEDIA_CONSUMER(pSelf)->video.in.height;
+ }
+
+ pSelf->nNegFps = (UINT32)TMEDIA_CONSUMER(pSelf)->video.fps;
+ pSelf->nNegWidth = (UINT32)TMEDIA_CONSUMER(pSelf)->video.display.width;
+ pSelf->nNegHeight = (UINT32)TMEDIA_CONSUMER(pSelf)->video.display.height;
+
+ TSK_DEBUG_INFO("D3D9 video consumer: fps=%d, width=%d, height=%d",
+ pSelf->nNegFps,
+ pSelf->nNegWidth,
+ pSelf->nNegHeight);
+
+ TMEDIA_CONSUMER(pSelf)->video.display.chroma = tmedia_chroma_rgb32;
+ TMEDIA_CONSUMER(pSelf)->decoder.codec_id = tmedia_codec_id_none; // means accept RAW fames
+
+ // The window handle is not created until the call is connect (incoming only) - At least on Internet Explorer 10
+ if(hWnd && !pSelf->bPluginWebRTC4All)
+ {
+ CHECK_HR(hr = CreateDeviceD3D9(hWnd, &pSelf->pDevice, &pSelf->pD3D, pSelf->d3dpp));
+ CHECK_HR(hr = CreateSwapChain(hWnd, pSelf->nNegWidth, pSelf->nNegHeight, pSelf->pDevice, &pSelf->pSwapChain));
+ }
+ else
+ {
+ if(hWnd && pSelf->bPluginWebRTC4All)
+ {
+ TSK_DEBUG_INFO("[MF consumer] HWND is defined but we detected webrtc4all...delaying D3D9 device creating until session get connected");
+ }
+ else
+ {
+ TSK_DEBUG_WARN("Delaying D3D9 device creation because HWND is not defined yet");
+ }
+ }
+
+bail:
+ pSelf->bPrepared = SUCCEEDED(hr);
+ return pSelf->bPrepared ? 0 : -1;
+}
+
+static int plugin_video_dshow_consumer_start(tmedia_consumer_t* self)
+{
+ plugin_video_dshow_consumer_t* pSelf = (plugin_video_dshow_consumer_t*)self;
+
+ if(!pSelf){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if(pSelf->bStarted){
+ TSK_DEBUG_INFO("D3D9 video consumer already started");
+ return 0;
+ }
+ if(!pSelf->bPrepared){
+ TSK_DEBUG_ERROR("D3D9 video consumer not prepared");
+ return -1;
+ }
+
+ HRESULT hr = S_OK;
+
+ pSelf->bPaused = false;
+ pSelf->bStarted = true;
+
+ return SUCCEEDED(hr) ? 0 : -1;
+}
+
+static int plugin_video_dshow_consumer_consume(tmedia_consumer_t* self, const void* buffer, tsk_size_t size, const tsk_object_t* proto_hdr)
+{
+ plugin_video_dshow_consumer_t* pSelf = (plugin_video_dshow_consumer_t*)self;
+
+ HRESULT hr = S_OK;
+ HWND hWnd = Window(pSelf);
+
+ IDirect3DSurface9 *pSurf = NULL;
+ IDirect3DSurface9 *pBB = NULL;
+
+ if(!pSelf)
+ {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1; // because of the mutex lock do it here
+ }
+
+ tsk_safeobj_lock(pSelf);
+
+ if(!buffer || !size)
+ {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ CHECK_HR(hr = E_INVALIDARG);
+ }
+
+ if(!pSelf->bStarted)
+ {
+ TSK_DEBUG_INFO("D3D9 video consumer not started");
+ CHECK_HR(hr = E_FAIL);
+ }
+
+ if(!hWnd)
+ {
+ TSK_DEBUG_INFO("Do not draw frame because HWND not set");
+ goto bail; // not an error as the application can decide to set the HWND at any time
+ }
+
+ if (!pSelf->bWindowHooked)
+ {
+ // Do not hook "hWnd" as it could be the fullscreen handle which is always hooked.
+ CHECK_HR(hr = HookWindow(pSelf, pSelf->hWindow));
+ }
+
+ if(!pSelf->pDevice || !pSelf->pD3D || !pSelf->pSwapChain)
+ {
+ if(pSelf->pDevice || pSelf->pD3D || pSelf->pSwapChain)
+ {
+ CHECK_HR(hr = E_POINTER); // They must be "all null" or "all valid"
+ }
+
+ if(hWnd)
+ {
+ // means HWND was not set but defined now
+ pSelf->nNegWidth = (UINT32)TMEDIA_CONSUMER(pSelf)->video.in.width;
+ pSelf->nNegHeight = (UINT32)TMEDIA_CONSUMER(pSelf)->video.in.height;
+
+ CHECK_HR(hr = CreateDeviceD3D9(hWnd, &pSelf->pDevice, &pSelf->pD3D, pSelf->d3dpp));
+ CHECK_HR(hr = CreateSwapChain(hWnd, pSelf->nNegWidth, pSelf->nNegHeight, pSelf->pDevice, &pSelf->pSwapChain));
+ }
+ }
+
+ if(pSelf->nNegWidth != TMEDIA_CONSUMER(pSelf)->video.in.width || pSelf->nNegHeight != TMEDIA_CONSUMER(pSelf)->video.in.height){
+ TSK_DEBUG_INFO("Negotiated and input video sizes are different:%d#%d or %d#%d",
+ pSelf->nNegWidth, TMEDIA_CONSUMER(pSelf)->video.in.width,
+ pSelf->nNegHeight, TMEDIA_CONSUMER(pSelf)->video.in.height);
+ // Update media type
+
+ SafeRelease(&pSelf->pSwapChain);
+ CHECK_HR(hr = CreateSwapChain(hWnd, (UINT32)TMEDIA_CONSUMER(pSelf)->video.in.width, (UINT32)TMEDIA_CONSUMER(pSelf)->video.in.height, pSelf->pDevice, &pSelf->pSwapChain));
+
+ pSelf->nNegWidth = (UINT32)TMEDIA_CONSUMER(pSelf)->video.in.width;
+ pSelf->nNegHeight = (UINT32)TMEDIA_CONSUMER(pSelf)->video.in.height;
+
+ // Update Destination will do noting if the window size haven't changed.
+ // Force updating the destination rect if negotiated size change
+ CHECK_HR(hr = UpdateDestinationRect(pSelf, TRUE/* Force */));
+ }
+
+ if(((pSelf->nNegWidth * pSelf->nNegHeight) << 2) != size)
+ {
+ TSK_DEBUG_ERROR("%u not valid as input size", size);
+ CHECK_HR(hr = E_FAIL);
+ }
+
+ CHECK_HR(hr = TestCooperativeLevel(pSelf));
+
+ CHECK_HR(hr = UpdateDestinationRect(pSelf));
+
+ CHECK_HR(hr = pSelf->pSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &pSurf));
+ CHECK_HR(hr = pSurf->LockRect(&pSelf->rcLock, NULL, D3DLOCK_NOSYSLOCK ));
+
+ // Fast copy() using MMX, SSE, or SSE2
+ // Only available on Vista or later: Use LoadLibrary() to get a pointer to the function
+ /*hr = MFCopyImage(
+ (BYTE*)pSelf->rcLock.pBits,
+ pSelf->rcLock.Pitch,
+ (BYTE*)buffer,
+ (pSelf->nNegWidth << 2),
+ (pSelf->nNegWidth << 2),
+ pSelf->nNegHeight
+ );*/
+
+ if(pSelf->rcLock.Pitch == (pSelf->nNegWidth << 2))
+ {
+ memcpy(pSelf->rcLock.pBits, buffer, size);
+ }
+ else
+ {
+ const BYTE* pSrcPtr = (const BYTE*)buffer;
+ BYTE* pDstPtr = (BYTE*)pSelf->rcLock.pBits;
+ UINT32 nDstPitch = pSelf->rcLock.Pitch;
+ UINT32 nSrcPitch = (pSelf->nNegWidth << 2);
+ for(UINT32 i = 0; i < pSelf->nNegHeight; ++i)
+ {
+ memcpy(pDstPtr, pSrcPtr, nSrcPitch);
+ pDstPtr += nDstPitch;
+ pSrcPtr += nSrcPitch;
+ }
+ }
+
+ if(FAILED(hr))
+ {
+ // unlock() before leaving
+ pSurf->UnlockRect();
+ CHECK_HR(hr);
+ }
+
+ CHECK_HR(hr = pSurf->UnlockRect());
+
+ // Color fill the back buffer
+ CHECK_HR(hr = pSelf->pDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBB));
+ CHECK_HR(hr = pSelf->pDevice->ColorFill(pBB, NULL, D3DCOLOR_XRGB(0xFF, 0xFF, 0xFF)));
+
+ // Resize keeping aspect ratio and Blit the frame (required)
+ hr = pSelf->pDevice->StretchRect(
+ pSurf,
+ NULL,
+ pBB,
+ &pSelf->rcDest/*NULL*/,
+ D3DTEXF_LINEAR
+ ); // could fail when display is being resized
+ if(SUCCEEDED(hr))
+ {
+ // Present the frame
+ CHECK_HR(hr = pSelf->pDevice->Present(NULL, NULL, NULL, NULL));
+ }
+ else
+ {
+ TSK_DEBUG_INFO("StretchRect returned ...%x", hr);
+ }
+
+bail:
+ SafeRelease(&pSurf);
+ SafeRelease(&pBB);
+
+ tsk_safeobj_unlock(pSelf);
+
+ return SUCCEEDED(hr) ? 0 : -1;
+}
+
+static int plugin_video_dshow_consumer_pause(tmedia_consumer_t* self)
+{
+ plugin_video_dshow_consumer_t* pSelf = (plugin_video_dshow_consumer_t*)self;
+
+ if(!pSelf){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if(!pSelf->bStarted)
+ {
+ TSK_DEBUG_INFO("MF video producer not started");
+ return 0;
+ }
+
+ HRESULT hr = S_OK;
+
+ pSelf->bPaused = true;
+
+ return SUCCEEDED(hr) ? 0 : -1;
+}
+
+static int plugin_video_dshow_consumer_stop(tmedia_consumer_t* self)
+{
+ plugin_video_dshow_consumer_t* pSelf = (plugin_video_dshow_consumer_t*)self;
+
+ if(!pSelf){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ HRESULT hr = S_OK;
+
+ pSelf->bStarted = false;
+ pSelf->bPaused = false;
+
+ if(pSelf->hWindowFullScreen)
+ {
+ ::InvalidateRect(pSelf->hWindowFullScreen, NULL, FALSE);
+ ::ShowWindow(pSelf->hWindowFullScreen, SW_HIDE);
+ }
+
+ // next start() will be called after prepare()
+ return _plugin_video_dshow_consumer_unprepare(pSelf);
+}
+
+static int _plugin_video_dshow_consumer_unprepare(plugin_video_dshow_consumer_t* pSelf)
+{
+ if(!pSelf){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if(pSelf->bStarted)
+ {
+ // plugin_win_mf_producer_video_stop(TMEDIA_PRODUCER(pSelf));
+ TSK_DEBUG_ERROR("Consumer must be stopped before calling unprepare");
+ return -1;
+ }
+
+ UnhookWindow(pSelf);
+
+ SafeRelease(&pSelf->pDevice);
+ SafeRelease(&pSelf->pD3D);
+ SafeRelease(&pSelf->pSwapChain);
+
+ pSelf->bPrepared = false;
+
+ return 0;
+}
+
+
+//
+// D3D9 video consumer object definition
+//
+/* constructor */
+static tsk_object_t* plugin_video_dshow_consumer_ctor(tsk_object_t * self, va_list * app)
+{
+ plugin_video_dshow_consumer_t *pSelf = (plugin_video_dshow_consumer_t *)self;
+ if(pSelf)
+ {
+ /* init base */
+ tmedia_consumer_init(TMEDIA_CONSUMER(pSelf));
+ TMEDIA_CONSUMER(pSelf)->video.display.chroma = tmedia_chroma_rgb32;
+ TMEDIA_CONSUMER(pSelf)->decoder.codec_id = tmedia_codec_id_none; // means accept RAW fames
+
+ /* init self */
+ tsk_safeobj_init(pSelf);
+ TMEDIA_CONSUMER(pSelf)->video.fps = 15;
+ TMEDIA_CONSUMER(pSelf)->video.display.width = 0; // use codec value
+ TMEDIA_CONSUMER(pSelf)->video.display.height = 0; // use codec value
+ TMEDIA_CONSUMER(pSelf)->video.display.auto_resize = tsk_true;
+
+ pSelf->pixelAR.Denominator = pSelf->pixelAR.Numerator = 1;
+ }
+ return self;
+}
+/* destructor */
+static tsk_object_t* plugin_video_dshow_consumer_dtor(tsk_object_t * self)
+{
+ plugin_video_dshow_consumer_t *pSelf = (plugin_video_dshow_consumer_t *)self;
+ if (pSelf) {
+ /* stop */
+ if (pSelf->bStarted)
+ {
+ plugin_video_dshow_consumer_stop(TMEDIA_CONSUMER(pSelf));
+ }
+
+ /* deinit base */
+ tmedia_consumer_deinit(TMEDIA_CONSUMER(pSelf));
+ /* deinit self */
+ _plugin_video_dshow_consumer_unprepare(pSelf);
+ tsk_safeobj_deinit(pSelf);
+ }
+
+ return self;
+}
+/* object definition */
+static const tsk_object_def_t plugin_video_dshow_consumer_def_s =
+{
+ sizeof(plugin_video_dshow_consumer_t),
+ plugin_video_dshow_consumer_ctor,
+ plugin_video_dshow_consumer_dtor,
+ tsk_null,
+};
+/* plugin definition*/
+static const tmedia_consumer_plugin_def_t plugin_video_dshow_consumer_plugin_def_s =
+{
+ &plugin_video_dshow_consumer_def_s,
+
+ tmedia_video,
+ "Microsoft DirectShow consumer (D3D9)",
+
+ plugin_video_dshow_consumer_set,
+ plugin_video_dshow_consumer_prepare,
+ plugin_video_dshow_consumer_start,
+ plugin_video_dshow_consumer_consume,
+ plugin_video_dshow_consumer_pause,
+ plugin_video_dshow_consumer_stop
+};
+const tmedia_consumer_plugin_def_t *plugin_video_dshow_consumer_plugin_def_t = &plugin_video_dshow_consumer_plugin_def_s;
+
+// Helper functions
+
+static HRESULT CreateDeviceD3D9(
+ HWND hWnd,
+ IDirect3DDevice9** ppDevice,
+ IDirect3D9 **ppD3D,
+ D3DPRESENT_PARAMETERS &d3dpp
+ )
+{
+ HRESULT hr = S_OK;
+
+ D3DDISPLAYMODE mode = { 0 };
+ D3DPRESENT_PARAMETERS pp = {0};
+
+ if(!ppDevice || *ppDevice || !ppD3D || *ppD3D)
+ {
+ CHECK_HR(hr = E_POINTER);
+ }
+
+ if(!(*ppD3D = Direct3DCreate9(D3D_SDK_VERSION)))
+ {
+ CHECK_HR(hr = E_OUTOFMEMORY);
+ }
+
+ CHECK_HR(hr = (*ppD3D)->GetAdapterDisplayMode(
+ D3DADAPTER_DEFAULT,
+ &mode
+ ));
+
+ CHECK_HR(hr = (*ppD3D)->CheckDeviceType(
+ D3DADAPTER_DEFAULT,
+ D3DDEVTYPE_HAL,
+ mode.Format,
+ D3DFMT_X8R8G8B8,
+ TRUE // windowed
+ ));
+ pp.BackBufferFormat = D3DFMT_X8R8G8B8;
+ pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
+ pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
+ pp.Windowed = TRUE;
+ pp.hDeviceWindow = hWnd;
+ CHECK_HR(hr = (*ppD3D)->CreateDevice(
+ D3DADAPTER_DEFAULT,
+ D3DDEVTYPE_HAL,
+ hWnd,
+ D3DCREATE_HARDWARE_VERTEXPROCESSING,
+ &pp,
+ ppDevice
+ ));
+
+ d3dpp = pp;
+
+bail:
+ if(FAILED(hr))
+ {
+ SafeRelease(ppD3D);
+ SafeRelease(ppDevice);
+ }
+ return hr;
+}
+
+static HRESULT TestCooperativeLevel(
+ struct plugin_video_dshow_consumer_s *pSelf
+ )
+{
+ HRESULT hr = S_OK;
+
+ if (!pSelf || !pSelf->pDevice)
+ {
+ CHECK_HR(hr = E_POINTER);
+ }
+
+ switch((hr = pSelf->pDevice->TestCooperativeLevel()))
+ {
+ case D3D_OK:
+ {
+ break;
+ }
+
+ case D3DERR_DEVICELOST:
+ {
+ hr = S_OK;
+ break;
+ }
+
+ case D3DERR_DEVICENOTRESET:
+ {
+ hr = ResetDevice(pSelf, TRUE);
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+
+ CHECK_HR(hr);
+
+bail:
+ return hr;
+}
+
+static HRESULT CreateSwapChain(
+ HWND hWnd,
+ UINT32 nFrameWidth,
+ UINT32 nFrameHeight,
+ IDirect3DDevice9* pDevice,
+ IDirect3DSwapChain9 **ppSwapChain
+ )
+{
+ HRESULT hr = S_OK;
+
+ D3DPRESENT_PARAMETERS pp = { 0 };
+
+ if(!pDevice || !ppSwapChain || *ppSwapChain)
+ {
+ CHECK_HR(hr = E_POINTER);
+ }
+
+ pp.BackBufferWidth = nFrameWidth;
+ pp.BackBufferHeight = nFrameHeight;
+ pp.Windowed = TRUE;
+ pp.SwapEffect = D3DSWAPEFFECT_FLIP;
+ pp.hDeviceWindow = hWnd;
+ pp.BackBufferFormat = D3DFMT_X8R8G8B8;
+ pp.Flags =
+ D3DPRESENTFLAG_VIDEO | D3DPRESENTFLAG_DEVICECLIP |
+ D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
+ pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
+ pp.BackBufferCount = NUM_BACK_BUFFERS;
+
+ CHECK_HR(hr = pDevice->CreateAdditionalSwapChain(&pp, ppSwapChain));
+
+bail:
+ return hr;
+}
+
+static inline HWND Window(struct plugin_video_dshow_consumer_s *pSelf)
+{
+ return pSelf ? (pSelf->bFullScreen ? pSelf->hWindowFullScreen : pSelf->hWindow) : NULL;
+}
+
+static inline LONG Width(const RECT& r)
+{
+ return r.right - r.left;
+}
+
+static inline LONG Height(const RECT& r)
+{
+ return r.bottom - r.top;
+}
+
+//-----------------------------------------------------------------------------
+// CorrectAspectRatio
+//
+// Converts a rectangle from the source's pixel aspect ratio (PAR) to 1:1 PAR.
+// Returns the corrected rectangle.
+//
+// For example, a 720 x 486 rect with a PAR of 9:10, when converted to 1x1 PAR,
+// is stretched to 720 x 540.
+// Copyright (C) Microsoft
+//-----------------------------------------------------------------------------
+
+static inline RECT CorrectAspectRatio(const RECT& src, const DSRatio& srcPAR)
+{
+ // Start with a rectangle the same size as src, but offset to the origin (0,0).
+ RECT rc = {0, 0, src.right - src.left, src.bottom - src.top};
+
+ if ((srcPAR.Numerator != 1) || (srcPAR.Denominator != 1))
+ {
+ // Correct for the source's PAR.
+
+ if (srcPAR.Numerator > srcPAR.Denominator)
+ {
+ // The source has "wide" pixels, so stretch the width.
+ rc.right = MulDiv(rc.right, srcPAR.Numerator, srcPAR.Denominator);
+ }
+ else if (srcPAR.Numerator < srcPAR.Denominator)
+ {
+ // The source has "tall" pixels, so stretch the height.
+ rc.bottom = MulDiv(rc.bottom, srcPAR.Denominator, srcPAR.Numerator);
+ }
+ // else: PAR is 1:1, which is a no-op.
+ }
+ return rc;
+}
+
+//-------------------------------------------------------------------
+// LetterBoxDstRect
+//
+// Takes a src rectangle and constructs the largest possible
+// destination rectangle within the specifed destination rectangle
+// such thatthe video maintains its current shape.
+//
+// This function assumes that pels are the same shape within both the
+// source and destination rectangles.
+// Copyright (C) Microsoft
+//-------------------------------------------------------------------
+
+static inline RECT LetterBoxRect(const RECT& rcSrc, const RECT& rcDst)
+{
+ // figure out src/dest scale ratios
+ int iSrcWidth = Width(rcSrc);
+ int iSrcHeight = Height(rcSrc);
+
+ int iDstWidth = Width(rcDst);
+ int iDstHeight = Height(rcDst);
+
+ int iDstLBWidth;
+ int iDstLBHeight;
+
+ if (MulDiv(iSrcWidth, iDstHeight, iSrcHeight) <= iDstWidth) {
+
+ // Column letter boxing ("pillar box")
+
+ iDstLBWidth = MulDiv(iDstHeight, iSrcWidth, iSrcHeight);
+ iDstLBHeight = iDstHeight;
+ }
+ else {
+
+ // Row letter boxing.
+
+ iDstLBWidth = iDstWidth;
+ iDstLBHeight = MulDiv(iDstWidth, iSrcHeight, iSrcWidth);
+ }
+
+
+ // Create a centered rectangle within the current destination rect
+
+ RECT rc;
+
+ LONG left = rcDst.left + ((iDstWidth - iDstLBWidth) >> 1);
+ LONG top = rcDst.top + ((iDstHeight - iDstLBHeight) >> 1);
+
+ SetRect(&rc, left, top, left + iDstLBWidth, top + iDstLBHeight);
+
+ return rc;
+}
+
+static inline HRESULT UpdateDestinationRect(plugin_video_dshow_consumer_t *pSelf, BOOL bForce /*= FALSE*/)
+{
+ HRESULT hr = S_OK;
+ HWND hwnd = Window(pSelf);
+
+ if(!pSelf)
+ {
+ CHECK_HR(hr = E_POINTER);
+ }
+
+ if(!hwnd)
+ {
+ CHECK_HR(hr = E_HANDLE);
+ }
+ RECT rcClient;
+ GetClientRect(hwnd, &rcClient);
+
+ // only update destination if window size changed
+ if(bForce || (rcClient.bottom != pSelf->rcWindow.bottom || rcClient.left != pSelf->rcWindow.left || rcClient.right != pSelf->rcWindow.right || rcClient.top != pSelf->rcWindow.top))
+ {
+ CHECK_HR(hr = ResetDevice(pSelf));
+
+ pSelf->rcWindow = rcClient;
+#if 1
+ RECT rcSrc = { 0, 0, pSelf->nNegWidth, pSelf->nNegHeight };
+ rcSrc = CorrectAspectRatio(rcSrc, pSelf->pixelAR);
+ pSelf->rcDest = LetterBoxRect(rcSrc, rcClient);
+#else
+ long w = rcClient.right - rcClient.left;
+ long h = rcClient.bottom - rcClient.top;
+ float ratio = ((float)pSelf->nNegWidth/(float)pSelf->nNegHeight);
+ // (w/h)=ratio =>
+ // 1) h=w/ratio
+ // and
+ // 2) w=h*ratio
+ pSelf->rcDest.right = (int)(w/ratio) > h ? (int)(h * ratio) : w;
+ pSelf->rcDest.bottom = (int)(pSelf->rcDest.right/ratio) > h ? h : (int)(pSelf->rcDest.right/ratio);
+ pSelf->rcDest.left = ((w - pSelf->rcDest.right) >> 1);
+ pSelf->rcDest.top = ((h - pSelf->rcDest.bottom) >> 1);
+#endif
+
+ //::InvalidateRect(hwnd, NULL, FALSE);
+ }
+
+bail:
+ return hr;
+}
+
+static HRESULT ResetDevice(plugin_video_dshow_consumer_t *pSelf, BOOL bUpdateDestinationRect /*= FALSE*/)
+{
+ HRESULT hr = S_OK;
+
+ tsk_safeobj_lock(pSelf);
+
+ HWND hWnd = Window(pSelf);
+
+ if (pSelf->pDevice)
+ {
+ D3DPRESENT_PARAMETERS d3dpp = pSelf->d3dpp;
+
+ hr = pSelf->pDevice->Reset(&d3dpp);
+
+ if (FAILED(hr))
+ {
+ SafeRelease(&pSelf->pDevice);
+ SafeRelease(&pSelf->pD3D);
+ SafeRelease(&pSelf->pSwapChain);
+ }
+ }
+
+ if (pSelf->pDevice == NULL && hWnd)
+ {
+ CHECK_HR(hr = CreateDeviceD3D9(hWnd, &pSelf->pDevice, &pSelf->pD3D, pSelf->d3dpp));
+ CHECK_HR(hr = CreateSwapChain(hWnd, pSelf->nNegWidth, pSelf->nNegHeight, pSelf->pDevice, &pSelf->pSwapChain));
+ }
+
+ if(bUpdateDestinationRect) // endless loop guard
+ {
+ CHECK_HR(hr = UpdateDestinationRect(pSelf));
+ }
+
+bail:
+ tsk_safeobj_unlock(pSelf);
+
+ return hr;
+}
+
+static HRESULT SetFullscreen(struct plugin_video_dshow_consumer_s *pSelf, BOOL bFullScreen)
+{
+ HRESULT hr = S_OK;
+ if(!pSelf)
+ {
+ CHECK_HR(hr = E_POINTER);
+ }
+
+ if(pSelf->bFullScreen != bFullScreen)
+ {
+ tsk_safeobj_lock(pSelf);
+ if(bFullScreen)
+ {
+ HWND hWnd = CreateFullScreenWindow(pSelf);
+ if(hWnd)
+ {
+ ::ShowWindow(hWnd, SW_SHOWDEFAULT);
+ ::UpdateWindow(hWnd);
+ }
+ }
+ else if(pSelf->hWindowFullScreen)
+ {
+ ::ShowWindow(pSelf->hWindowFullScreen, SW_HIDE);
+ }
+ pSelf->bFullScreen = bFullScreen;
+ if(pSelf->bPrepared)
+ {
+ hr = ResetDevice(pSelf);
+ }
+ tsk_safeobj_unlock(pSelf);
+
+ CHECK_HR(hr);
+ }
+
+bail:
+ return hr;
+}
+
+static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch(uMsg)
+ {
+ case WM_CREATE:
+ case WM_SIZE:
+ case WM_MOVE:
+ {
+ struct plugin_video_dshow_consumer_s* pSelf = dynamic_cast<struct plugin_video_dshow_consumer_s*>((struct plugin_video_dshow_consumer_s*)GetPropA(hWnd, "Self"));
+ if (pSelf)
+ {
+
+ }
+ break;
+ }
+#if 0
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ HDC hdc = BeginPaint(hWnd, &ps);
+ ps.fErase = FALSE;
+
+ RECT rc;
+ GetBoundsRect(hdc, &rc, 0);
+ FillRect(hdc, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH));
+
+ EndPaint(hWnd, &ps);
+ break;
+ }
+#endif
+
+ case WM_ERASEBKGND:
+ {
+ return TRUE; // avoid background erasing.
+ }
+
+
+ case WM_CHAR:
+ case WM_KEYUP:
+ {
+ struct plugin_video_dshow_consumer_s* pSelf = dynamic_cast<struct plugin_video_dshow_consumer_s*>((struct plugin_video_dshow_consumer_s*)GetPropA(hWnd, "Self"));
+ if (pSelf)
+ {
+ SetFullscreen(pSelf, FALSE);
+ }
+
+ break;
+ }
+ }
+
+ return DefWindowProc(hWnd, uMsg, wParam, lParam);
+}
+
+static HWND CreateFullScreenWindow(struct plugin_video_dshow_consumer_s *pSelf)
+{
+ HRESULT hr = S_OK;
+
+ if(!pSelf)
+ {
+ return NULL;
+ }
+
+ if(!pSelf->hWindowFullScreen)
+ {
+ WNDCLASS wc = {0};
+
+ wc.lpfnWndProc = WndProc;
+ wc.hInstance = GetModuleHandle(NULL);
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.lpszClassName = L"WindowClass";
+ RegisterClass(&wc);
+ pSelf->hWindowFullScreen = ::CreateWindowEx(
+ NULL,
+ wc.lpszClassName,
+ L"Doubango's Video Consumer Fullscreen",
+ WS_EX_TOPMOST | WS_POPUP,
+ 0, 0,
+ GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN),
+ NULL,
+ NULL,
+ GetModuleHandle(NULL),
+ NULL);
+
+ SetPropA(pSelf->hWindowFullScreen, "Self", pSelf);
+ }
+ return pSelf->hWindowFullScreen;
+}
+
+static HRESULT HookWindow(plugin_video_dshow_consumer_t *pSelf, HWND hWnd)
+{
+ HRESULT hr = S_OK;
+
+ tsk_safeobj_lock(pSelf);
+
+ CHECK_HR(hr = UnhookWindow(pSelf));
+
+ if ((pSelf->hWindow = hWnd)) {
+ pSelf->wndProc = (WNDPROC)SetWindowLongPtr(pSelf->hWindow, GWLP_WNDPROC, (LONG_PTR)WndProc);
+ if (!pSelf->wndProc) {
+ TSK_DEBUG_ERROR("HookWindowLongPtr() failed with errcode=%d", GetLastError());
+ CHECK_HR(hr = E_FAIL);
+ }
+ pSelf->bWindowHooked = TRUE;
+ }
+bail:
+ tsk_safeobj_unlock(pSelf);
+ return S_OK;
+}
+
+static HRESULT UnhookWindow(struct plugin_video_dshow_consumer_s *pSelf)
+{
+ tsk_safeobj_lock(pSelf);
+ if (pSelf->hWindow && pSelf->wndProc) {
+ SetWindowLongPtr(pSelf->hWindow, GWLP_WNDPROC, (LONG_PTR)pSelf->wndProc);
+ pSelf->wndProc = NULL;
+ }
+ if(pSelf->hWindow)
+ {
+ ::InvalidateRect(pSelf->hWindow, NULL, FALSE);
+ }
+ pSelf->bWindowHooked = FALSE;
+ tsk_safeobj_unlock(pSelf);
+ return S_OK;
+}
+
+#else /* !PLUGIN_DS_CV_USE_D3D9 */
+
+typedef struct plugin_video_dshow_consumer_s
+{
+ TMEDIA_DECLARE_CONSUMER;
+
+ DSDisplay* display;
+ INT64 window;
+
+ tsk_bool_t plugin_firefox;
+ tsk_bool_t started;
+ tsk_bool_t create_on_ui_thread;
+}
+plugin_video_dshow_consumer_t;
+
+
+
+/* ============ Media Consumer Interface ================= */
+static int plugin_video_dshow_consumer_set(tmedia_consumer_t *self, const tmedia_param_t* param)
+{
+ int ret = 0;
+
+ if(!self || !param){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if(param->value_type == tmedia_pvt_int64){
+ if(tsk_striequals(param->key, "remote-hwnd")){
+ DSCONSUMER(self)->window = (INT64)*((int64_t*)param->value);
+ if(DSCONSUMER(self)->display){
+ if(DSCONSUMER(self)->window){
+ DSCONSUMER(self)->display->attach(DSCONSUMER(self)->window);
+ }
+ else{
+ DSCONSUMER(self)->display->detach();
+ }
+ }
+ }
+ }
+ else if(param->value_type == tmedia_pvt_int32){
+ if(tsk_striequals(param->key, "fullscreen")){
+ if(DSCONSUMER(self)->display){
+ DSCONSUMER(self)->display->setFullscreen(*((int32_t*)param->value) != 0);
+ }
+ }
+ else if(tsk_striequals(param->key, "create-on-current-thead")){
+ DSCONSUMER(self)->create_on_ui_thread = *((int32_t*)param->value) ? tsk_false : tsk_true;
+ }
+ else if(tsk_striequals(param->key, "plugin-firefox")){
+ DSCONSUMER(self)->plugin_firefox = (*((int32_t*)param->value) != 0);
+ if(DSCONSUMER(self)->display){
+ DSCONSUMER(self)->display->setPluginFirefox((DSCONSUMER(self)->plugin_firefox == tsk_true));
+ }
+ }
+ }
+
+ return ret;
+}
+
+
+static int plugin_video_dshow_consumer_prepare(tmedia_consumer_t* self, const tmedia_codec_t* codec)
+{
+ plugin_video_dshow_consumer_t* consumer = (plugin_video_dshow_consumer_t*)self;
+
+ if(!consumer || !codec && codec->plugin){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ TMEDIA_CONSUMER(consumer)->video.fps = TMEDIA_CODEC_VIDEO(codec)->in.fps;
+ TMEDIA_CONSUMER(consumer)->video.in.width = TMEDIA_CODEC_VIDEO(codec)->in.width;
+ TMEDIA_CONSUMER(consumer)->video.in.height = TMEDIA_CODEC_VIDEO(codec)->in.height;
+
+ if(!TMEDIA_CONSUMER(consumer)->video.display.width){
+ TMEDIA_CONSUMER(consumer)->video.display.width = TMEDIA_CONSUMER(consumer)->video.in.width;
+ }
+ if(!TMEDIA_CONSUMER(consumer)->video.display.height){
+ TMEDIA_CONSUMER(consumer)->video.display.height = TMEDIA_CONSUMER(consumer)->video.in.height;
+ }
+
+ return 0;
+}
+
+static int plugin_video_dshow_consumer_start(tmedia_consumer_t* self)
+{
+ plugin_video_dshow_consumer_t* consumer = (plugin_video_dshow_consumer_t*)self;
+
+ if(!consumer){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if(consumer->started){
+ return 0;
+ }
+
+ // create display on UI thread
+ if(!consumer->display){
+ if (consumer->create_on_ui_thread) createOnUIThead(reinterpret_cast<HWND>((void*)consumer->window), (void**)&consumer->display, true, false);
+ else createOnCurrentThead(reinterpret_cast<HWND>((void*)consumer->window), (void**)&consumer->display, true, false);
+
+ if(!consumer->display){
+ TSK_DEBUG_ERROR("Failed to create display");
+ return -2;
+ }
+ }
+
+ // Set parameters
+ consumer->display->setPluginFirefox((consumer->plugin_firefox == tsk_true));
+ consumer->display->setFps(TMEDIA_CONSUMER(consumer)->video.fps);
+ // do not change the display size: see hook()
+ // consumer->display->setSize(TMEDIA_CONSUMER(consumer)->video.display.width, TMEDIA_CONSUMER(consumer)->video.display.height);
+ if(consumer->window){
+ consumer->display->attach(consumer->window);
+ }
+
+ // Start display
+ consumer->display->start();
+ consumer->started = tsk_true;
+
+ return 0;
+}
+
+static int plugin_video_dshow_consumer_consume(tmedia_consumer_t* self, const void* buffer, tsk_size_t size, const tsk_object_t* proto_hdr)
+{
+ plugin_video_dshow_consumer_t* consumer = (plugin_video_dshow_consumer_t*)self;
+ if(consumer && consumer->display && buffer){
+ consumer->display->handleVideoFrame(buffer, TMEDIA_CONSUMER(consumer)->video.display.width, TMEDIA_CONSUMER(consumer)->video.display.height);
+ return 0;
+ }
+ else{
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+}
+
+static int plugin_video_dshow_consumer_pause(tmedia_consumer_t* self)
+{
+ plugin_video_dshow_consumer_t* consumer = (plugin_video_dshow_consumer_t*)self;
+
+ if(!consumer){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if(!consumer->display){
+ TSK_DEBUG_ERROR("Invalid internal grabber");
+ return -2;
+ }
+
+ //consumer->display->pause();
+
+ return 0;
+}
+
+static int plugin_video_dshow_consumer_stop(tmedia_consumer_t* self)
+{
+ plugin_video_dshow_consumer_t* consumer = (plugin_video_dshow_consumer_t*)self;
+
+ if(!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if(!consumer->started){
+ return 0;
+ }
+
+ if(!consumer->display){
+ TSK_DEBUG_ERROR("Invalid internal display");
+ return -2;
+ }
+
+ TSK_DEBUG_INFO("Before stopping DirectShow consumer");
+ consumer->display->stop();
+ consumer->started = tsk_false;
+ TSK_DEBUG_INFO("After stopping DirectShow consumer");
+
+ return 0;
+}
+
+
+//
+// DirectShow consumer object definition
+//
+/* constructor */
+static tsk_object_t* plugin_video_dshow_consumer_ctor(tsk_object_t * self, va_list * app)
+{
+ CoInitializeEx(NULL, COINIT_MULTITHREADED);
+
+ plugin_video_dshow_consumer_t *consumer = (plugin_video_dshow_consumer_t *)self;
+ if(consumer){
+ /* init base */
+ tmedia_consumer_init(TMEDIA_CONSUMER(consumer));
+ TMEDIA_CONSUMER(consumer)->video.display.chroma = tmedia_chroma_bgr24; // RGB24 on x86 (little endians) stored as BGR24
+
+ /* init self */
+ consumer->create_on_ui_thread = tsk_true;
+ TMEDIA_CONSUMER(consumer)->video.fps = 15;
+ TMEDIA_CONSUMER(consumer)->video.display.width = 352;
+ TMEDIA_CONSUMER(consumer)->video.display.height = 288;
+ TMEDIA_CONSUMER(consumer)->video.display.auto_resize = tsk_true;
+ }
+ return self;
+}
+/* destructor */
+static tsk_object_t* plugin_video_dshow_consumer_dtor(tsk_object_t * self)
+{
+ plugin_video_dshow_consumer_t *consumer = (plugin_video_dshow_consumer_t *)self;
+ if(consumer){
+
+ /* stop */
+ if(consumer->started){
+ plugin_video_dshow_consumer_stop((tmedia_consumer_t*)self);
+ }
+
+ /* deinit base */
+ tmedia_consumer_deinit(TMEDIA_CONSUMER(consumer));
+ /* deinit self */
+ SAFE_DELETE_PTR(consumer->display);
+
+ }
+
+ return self;
+}
+/* object definition */
+static const tsk_object_def_t plugin_video_dshow_consumer_def_s =
+{
+ sizeof(plugin_video_dshow_consumer_t),
+ plugin_video_dshow_consumer_ctor,
+ plugin_video_dshow_consumer_dtor,
+ tsk_null,
+};
+/* plugin definition*/
+static const tmedia_consumer_plugin_def_t plugin_video_dshow_consumer_plugin_def_s =
+{
+ &plugin_video_dshow_consumer_def_s,
+
+ tmedia_video,
+ "Microsoft DirectShow consumer (using custom source)",
+
+ plugin_video_dshow_consumer_set,
+ plugin_video_dshow_consumer_prepare,
+ plugin_video_dshow_consumer_start,
+ plugin_video_dshow_consumer_consume,
+ plugin_video_dshow_consumer_pause,
+ plugin_video_dshow_consumer_stop
+};
+const tmedia_consumer_plugin_def_t *plugin_video_dshow_consumer_plugin_def_t = &plugin_video_dshow_consumer_plugin_def_s;
+
+#endif /* PLUGIN_DS_CV_USE_D3D9 */
+
diff --git a/plugins/pluginDirectShow/plugin_video_dshow_producer.cxx b/plugins/pluginDirectShow/plugin_video_dshow_producer.cxx
new file mode 100644
index 0000000..61aa929
--- /dev/null
+++ b/plugins/pluginDirectShow/plugin_video_dshow_producer.cxx
@@ -0,0 +1,276 @@
+/* Copyright (C) 2011-2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*/
+#include "internals/DSGrabber.h"
+#include "internals/DSDisplay.h"
+#include "internals/DSUtils.h"
+
+#include "tinymedia/tmedia_producer.h"
+
+#include "tsk_string.h"
+#include "tsk_debug.h"
+
+#define DSPRODUCER(self) ((plugin_video_dshow_producer_t*)(self))
+
+typedef struct plugin_video_dshow_producer_s
+{
+ TMEDIA_DECLARE_PRODUCER;
+
+ DSGrabber* grabber;
+ INT64 previewHwnd;
+
+ tsk_bool_t plugin_firefox;
+ tsk_bool_t started;
+ tsk_bool_t mute;
+ tsk_bool_t create_on_ui_thread;
+}
+plugin_video_dshow_producer_t;
+
+// Producer callback (From DirectShow Grabber to our plugin)
+static int plugin_video_dshow_plugin_cb(const void* callback_data, const void* buffer, tsk_size_t size)
+{
+ const plugin_video_dshow_producer_t* producer = (const plugin_video_dshow_producer_t*)callback_data;
+
+ if(producer && TMEDIA_PRODUCER(producer)->enc_cb.callback){
+ TMEDIA_PRODUCER(producer)->enc_cb.callback(TMEDIA_PRODUCER(producer)->enc_cb.callback_data, buffer, size);
+ }
+
+ return 0;
+}
+
+
+/* ============ Media Producer Interface ================= */
+static int plugin_video_dshow_producer_set(tmedia_producer_t *self, const tmedia_param_t* param)
+{
+ int ret = 0;
+ plugin_video_dshow_producer_t* producer = (plugin_video_dshow_producer_t*)self;
+
+ if(!producer || !param){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if(param->value_type == tmedia_pvt_int64){
+ if(tsk_striequals(param->key, "local-hwnd")){
+ DSPRODUCER(producer)->previewHwnd = (INT64)*((int64_t*)param->value);
+ if(DSPRODUCER(producer)->grabber && DSPRODUCER(self)->grabber->preview){
+ DSPRODUCER(producer)->grabber->preview->attach(DSPRODUCER(producer)->previewHwnd);
+ }
+ }
+ }
+ else if(param->value_type == tmedia_pvt_int32){
+ if(tsk_striequals(param->key, "mute")){
+ producer->mute = (TSK_TO_INT32((uint8_t*)param->value) != 0);
+ if(producer->started){
+ if (producer->mute) {
+ producer->grabber->pause();
+ }
+ else{
+ producer->grabber->start();
+ }
+ }
+ }
+ else if(tsk_striequals(param->key, "create-on-current-thead")){
+ producer->create_on_ui_thread = *((int32_t*)param->value) ? tsk_false : tsk_true;
+ }
+ else if(tsk_striequals(param->key, "plugin-firefox")){
+ producer->plugin_firefox = (*((int32_t*)param->value) != 0);
+ if(producer->grabber){
+ producer->grabber->setPluginFirefox((producer->plugin_firefox == tsk_true));
+ }
+ }
+ }
+
+ return ret;
+}
+
+static int plugin_video_dshow_producer_prepare(tmedia_producer_t* self, const tmedia_codec_t* codec)
+{
+ plugin_video_dshow_producer_t* producer = (plugin_video_dshow_producer_t*)self;
+
+ if(!producer || !codec && codec->plugin){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ TMEDIA_PRODUCER(producer)->video.fps = TMEDIA_CODEC_VIDEO(codec)->out.fps;
+ TMEDIA_PRODUCER(producer)->video.width = TMEDIA_CODEC_VIDEO(codec)->out.width;
+ TMEDIA_PRODUCER(producer)->video.height = TMEDIA_CODEC_VIDEO(codec)->out.height;
+
+ return 0;
+}
+
+static int plugin_video_dshow_producer_start(tmedia_producer_t* self)
+{
+ plugin_video_dshow_producer_t* producer = (plugin_video_dshow_producer_t*)self;
+
+ if(!producer){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if (producer->started) {
+ return 0;
+ }
+
+ // create grabber on UI thread
+ if (!producer->grabber) {
+ static BOOL __isDisplayFalse = FALSE;
+ static BOOL __isScreenCastFalse = FALSE;
+ if(producer->create_on_ui_thread) createOnUIThead(reinterpret_cast<HWND>((void*)DSPRODUCER(producer)->previewHwnd), (void**)&producer->grabber, __isDisplayFalse, __isScreenCastFalse);
+ else createOnCurrentThead(reinterpret_cast<HWND>((void*)DSPRODUCER(producer)->previewHwnd), (void**)&producer->grabber, __isDisplayFalse, __isScreenCastFalse);
+ if (!producer->grabber) {
+ TSK_DEBUG_ERROR("Failed to create grabber");
+ return -2;
+ }
+ }
+ producer->grabber->setPluginFirefox((producer->plugin_firefox == tsk_true));
+
+ //set Source device
+ producer->grabber->setCaptureDevice("Null");
+
+ // set parameters
+ producer->grabber->setCaptureParameters((int)TMEDIA_PRODUCER(producer)->video.width, (int)TMEDIA_PRODUCER(producer)->video.height, TMEDIA_PRODUCER(producer)->video.fps);
+
+ // set callback function
+ producer->grabber->setCallback(plugin_video_dshow_plugin_cb, producer);
+
+ // attach preview
+ if(producer->grabber->preview){
+ if(producer->previewHwnd){
+ producer->grabber->preview->attach(producer->previewHwnd);
+ }
+ producer->grabber->preview->setSize((int)TMEDIA_PRODUCER(producer)->video.width, (int)TMEDIA_PRODUCER(producer)->video.height);
+ }
+
+ // start grabber
+ if(!producer->mute){
+ producer->grabber->start();
+ }
+ producer->started = tsk_true;
+
+ return 0;
+}
+
+static int plugin_video_dshow_producer_pause(tmedia_producer_t* self)
+{
+ plugin_video_dshow_producer_t* producer = (plugin_video_dshow_producer_t*)self;
+
+ if(!producer){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if(!producer->grabber){
+ TSK_DEBUG_ERROR("Invalid internal grabber");
+ return -2;
+ }
+
+ producer->grabber->pause();
+
+ return 0;
+}
+
+static int plugin_video_dshow_producer_stop(tmedia_producer_t* self)
+{
+ plugin_video_dshow_producer_t* producer = (plugin_video_dshow_producer_t*)self;
+
+ if(!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if(!producer->started){
+ return 0;
+ }
+
+ if(!producer->grabber){
+ TSK_DEBUG_ERROR("Invalid internal grabber");
+ return -2;
+ }
+
+ producer->grabber->stop();
+ producer->started = tsk_false;
+
+ return 0;
+}
+
+
+//
+// WaveAPI producer object definition
+//
+/* constructor */
+static tsk_object_t* plugin_video_dshow_producer_ctor(tsk_object_t * self, va_list * app)
+{ plugin_video_dshow_producer_t *producer = (plugin_video_dshow_producer_t *)self;
+ if (producer) {
+ /* init base */
+ tmedia_producer_init(TMEDIA_PRODUCER(producer));
+ TMEDIA_PRODUCER(producer)->video.chroma = tmedia_chroma_bgr24; // RGB24 on x86 (little endians) stored as BGR24
+ /* init self with default values*/
+ producer->create_on_ui_thread = tsk_true;
+ TMEDIA_PRODUCER(producer)->video.fps = 15;
+ TMEDIA_PRODUCER(producer)->video.width = 352;
+ TMEDIA_PRODUCER(producer)->video.height = 288;
+ }
+ return self;
+}
+/* destructor */
+static tsk_object_t* plugin_video_dshow_producer_dtor(tsk_object_t * self)
+{
+ plugin_video_dshow_producer_t *producer = (plugin_video_dshow_producer_t *)self;
+ if(producer){
+ /* stop */
+ if(producer->started){
+ plugin_video_dshow_producer_stop((tmedia_producer_t*)self);
+ }
+
+ /* for safety */
+ if(producer->grabber){
+ producer->grabber->setCallback(tsk_null, tsk_null);
+ }
+
+ /* deinit base */
+ tmedia_producer_deinit(TMEDIA_PRODUCER(producer));
+ /* deinit self */
+ SAFE_DELETE_PTR(producer->grabber);
+ }
+
+ return self;
+}
+/* object definition */
+static const tsk_object_def_t plugin_video_dshow_producer_def_s =
+{
+ sizeof(plugin_video_dshow_producer_t),
+ plugin_video_dshow_producer_ctor,
+ plugin_video_dshow_producer_dtor,
+ tsk_null,
+};
+/* plugin definition*/
+static const tmedia_producer_plugin_def_t plugin_video_dshow_producer_plugin_def_s =
+{
+ &plugin_video_dshow_producer_def_s,
+
+ tmedia_video,
+ "Microsoft DirectShow producer",
+
+ plugin_video_dshow_producer_set,
+ plugin_video_dshow_producer_prepare,
+ plugin_video_dshow_producer_start,
+ plugin_video_dshow_producer_pause,
+ plugin_video_dshow_producer_stop
+};
+const tmedia_producer_plugin_def_t *plugin_video_dshow_producer_plugin_def_t = &plugin_video_dshow_producer_plugin_def_s;
diff --git a/plugins/pluginDirectShow/version.rc b/plugins/pluginDirectShow/version.rc
new file mode 100644
index 0000000..fc0f489
--- /dev/null
+++ b/plugins/pluginDirectShow/version.rc
@@ -0,0 +1,102 @@
+// Microsoft Visual C++ generated resource script.
+//
+// #include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 2.0.0.1156
+ PRODUCTVERSION 2.0.0.1156
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "Doubango Telecom"
+ VALUE "FileDescription", "Doubango IMS Framework DirectShow Plugin"
+ VALUE "FileVersion", "2.0.0.1156"
+ VALUE "InternalName", "pluginDirectShow.dll"
+ VALUE "LegalCopyright", "(c) 2010-2013 Doubango Telecom. All rights reserved."
+ VALUE "OriginalFilename", "pluginDirectShow.dll"
+ VALUE "ProductName", "Doubango IMS Framework DirectShow Plugin"
+ VALUE "ProductVersion", "2.0.0.1156"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
OpenPOWER on IntegriCloud