diff options
author | Mamadou DIOP <bossiel@yahoo.fr> | 2015-08-17 01:56:35 +0200 |
---|---|---|
committer | Mamadou DIOP <bossiel@yahoo.fr> | 2015-08-17 01:56:35 +0200 |
commit | 631fffee8a28b1bec5ed1f1d26a20e0135967f99 (patch) | |
tree | 74afe3bf3efe15aa82bcd0272b2b0f4d48c2d837 /plugins/pluginDirectShow/internals | |
parent | 7908865936604036e6f200f1b5e069f8752f3a3a (diff) | |
download | doubango-631fffee8a28b1bec5ed1f1d26a20e0135967f99.zip doubango-631fffee8a28b1bec5ed1f1d26a20e0135967f99.tar.gz |
-
Diffstat (limited to 'plugins/pluginDirectShow/internals')
47 files changed, 8176 insertions, 0 deletions
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, ¶m1, ¶m2, 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, ¤tFilter, &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, ¤tFilter, &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 */ |