diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ee7d0b3f..77ce7de7b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -363,6 +363,7 @@ FIND_PACKAGE(OurDCMTK) FIND_PACKAGE(OpenAL) FIND_PACKAGE(XUL) FIND_PACKAGE(FFmpeg) +FIND_PACKAGE(DirectShow) FIND_PACKAGE(SDL) #use pkg-config to find various modues diff --git a/CMakeModules/FindDirectShow.cmake b/CMakeModules/FindDirectShow.cmake new file mode 100644 index 000000000..e3729facf --- /dev/null +++ b/CMakeModules/FindDirectShow.cmake @@ -0,0 +1,58 @@ +# Locate directshow +# This module defines +# DIRECTSHOW_LIBRARIES +# DIRECTSHOW_FOUND, if false, do not try to link to directshow +# DIRECTSHOW_INCLUDE_DIR, where to find the headers +# +# $DIRECTSHOW_DIR is an environment variable that would +# point to the this path in the plateform devkit (Samples\Multimedia\DirectShow) +# +# Created by Cedric Pinson. +# + + +SET(DIRECTSHOW_FOUND "NO") +SET(DIRECTSHOW_SAMPLE_ROOT "$ENV{DIRECTSHOW_DIR}" CACHE PATH "Location of DirectShow sample in devkit") + +IF(WIN32) + FIND_PATH(DIRECTSHOW_STRMBASE_INCLUDE_DIRS renbase.h + PATHS + ${DIRECTSHOW_SAMPLE_ROOT}/BaseClasses/ + $ENV{DIRECTSHOW_SAMPLE_ROOT}/BaseClasses/ + DOC "Location of DirectShow Base include on the windows devkit" + ) + + FIND_LIBRARY(DIRECTSHOW_STRMBASE_LIBRARY_RELEASE strmbase + PATHS + ${DIRECTSHOW_SAMPLE_ROOT}/BaseClasses/Release_MBCS/ # sdk 6.1 + $ENV{DIRECTSHOW_SAMPLE_ROOT}/BaseClasses/Release_MBCS/ # sdk 6.1 + ${DIRECTSHOW_SAMPLE_ROOT}/BaseClasses/Release/ # sdk 2003 + $ENV{DIRECTSHOW_SAMPLE_ROOT}/BaseClasses/Release/ # sdk 2003 + DOC "Location of DirectShow Base library on the windows devkit" + ) + + FIND_LIBRARY(DIRECTSHOW_STRMBASE_LIBRARY_DEBUG strmbasd + PATHS + ${DIRECTSHOW_SAMPLE_ROOT}/BaseClasses/Debug_MBCS/ # sdk 6.1 + $ENV{DIRECTSHOW_SAMPLE_ROOT}/BaseClasses/Debug_MBCS/ # sdk 6.1 + ${DIRECTSHOW_SAMPLE_ROOT}/BaseClasses/Debug/ # sdk 2003 + $ENV{DIRECTSHOW_SAMPLE_ROOT}/BaseClasses/Debug/ # sdk 2003 + DOC "Location of DirectShow Base library on the windows devkit" + ) + + IF (DIRECTSHOW_STRMBASE_INCLUDE_DIRS AND DIRECTSHOW_STRMBASE_LIBRARY_RELEASE) + SET(WIN_LIBS winmm d3d9 d3dx9 kernel32 user32 gdi32 winspool shell32 ole32 oleaut32 uuid comdlg32 advapi32) + SET(DIRECTSHOW_FOUND "YES") + SET(DIRECTSHOW_LIBRARY_DEBUG + ${DIRECTSHOW_STRMBASE_LIBRARY_DEBUG} + ) + SET(DIRECTSHOW_LIBRARY + ${DIRECTSHOW_STRMBASE_LIBRARY_RELEASE} + ) + SET(DIRECTSHOW_INLUDE_DIRS + ${DIRECTSHOW_STRMBASE_INCLUDE_DIRS} + ) + + ENDIF() + +ENDIF() diff --git a/src/osgPlugins/CMakeLists.txt b/src/osgPlugins/CMakeLists.txt index 10feaf03b..d412a7040 100644 --- a/src/osgPlugins/CMakeLists.txt +++ b/src/osgPlugins/CMakeLists.txt @@ -208,6 +208,10 @@ IF(FFMPEG_FOUND) ADD_SUBDIRECTORY(ffmpeg) ENDIF() +IF(DIRECTSHOW_FOUND) + ADD_SUBDIRECTORY(directshow) +ENDIF() + # IF(OPENAL_FOUND) # ADD_SUBDIRECTORY(OpenAL) # ENDIF() diff --git a/src/osgPlugins/directshow/CMakeLists.txt b/src/osgPlugins/directshow/CMakeLists.txt new file mode 100644 index 000000000..184ad1d84 --- /dev/null +++ b/src/osgPlugins/directshow/CMakeLists.txt @@ -0,0 +1,68 @@ +# For visual studio express 2005 and windows plateforme sdk 2003 +# i have some problem with the windows sdk to build the BaseClasses, so +# here some point that will help to fix this. +# https://blogs.msdn.com/mikewasson/archive/2005/05/23/421116.aspx + +# use this link to downloads vc project to build strmbase library +# http://www.microsoft.com/downloads/thankyou.aspx?familyId=8af0afa9-1383-44b4-bc8b-7d6315212323&displayLang=en + +# to build strmbase.lib +# modify clutil.h line 278 +# operator=(LONG); +# to +# (LONG) operator=(LONG); + +# add in includes directory +# C:\Program Files\Microsoft Platform SDK for Windows Server 2003 R2\Include\atl + +# modify winutil.cpp line 2104 +# for (Count = 0;Count < Result;Count++) { +# to +# for (UINT Count = 0;Count < Result;Count++) { + +# modify winutil.cpp line 2123 +# for (Count = PalLoCount;INT(Count) < min(PalHiStart,iColours);Count++) { +# to +# for (UINT Count = PalLoCount;INT(Count) < min(PalHiStart,iColours);Count++) { + +# modify wxdebug.cpp line 564 +# static g_dwLastRefresh = 0; +# to +# static DWORD g_dwLastRefresh = 0; + +# modify outputq.cpp line 6134 +# LONG iLost = 0; +# for (long iDone = 0; +# to +# LONG iLost = 0; +# long iDone = 0; +# for (iDone = 0; + +# In the properties of the project there is a fixed path to link with strmiids.lib. Replace the ../../../.. by the name of the library +# only, then the linker will find the strmiids.lib + +# After those step it should compile, becareful using unicode version will result undefined symbol ... so use multibyte version instead +# +# End For visual studio express 2005 and windows plateforme sdk 2003 + + +INCLUDE_DIRECTORIES( ${DIRECTSHOW_INLUDE_DIRS} ) +SET (TARGET_EXTERNAL_LIBRARIES + quartz comsuppw winmm d3d9 d3dx9 kernel32 user32 gdi32 winspool shell32 ole32 oleaut32 uuid comdlg32 advapi32 + ) + +SET(TARGET_SRC + ReaderWriterDirectShow.cpp + DirectShowTexture.cpp +) + +SET(TARGET_H + DirectShowTexture +) +SET(TARGET_LIBRARIES_VARS DIRECTSHOW_LIBRARY ) + +#### end var setup ### +SETUP_PLUGIN(directshow directshow) +SET_TARGET_PROPERTIES("${TARGET_DEFAULT_PREFIX}${TARGET_NAME}" PROPERTIES LINK_FLAGS "/NODEFAULTLIB:atlthunk") + + diff --git a/src/osgPlugins/directshow/DirectShowTexture b/src/osgPlugins/directshow/DirectShowTexture new file mode 100644 index 000000000..9d57bd861 --- /dev/null +++ b/src/osgPlugins/directshow/DirectShowTexture @@ -0,0 +1,125 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 2009 Tharsis Software + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library 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 + * OpenSceneGraph Public License for more details. + * + * Authors: + * Cedric Pinson +*/ + +#ifndef DirectShowTexture +#define DirectShowTexture 1 + +#include +#include +#include +#include +#include +#include +#include + +//----------------------------------------------------------------------------- +// Define GUID for Texture Renderer +// {71771540-2017-11cf-AE26-0020AFD79767} +//----------------------------------------------------------------------------- +struct __declspec(uuid("{71771540-2017-11cf-ae26-0020afd79767}")) CLSID_TextureRenderer; + +class CTextureRenderer; + +class DirectShowImageStream : public osg::ImageStream +{ +public: + typedef std::map Options; + +protected: + osg::observer_ptr _renderer; + mutable OpenThreads::Mutex _mutex; + Options _options; + +public: + DirectShowImageStream(); + ~DirectShowImageStream(); + DirectShowImageStream(const DirectShowImageStream & image, const osg::CopyOp & copyop = osg::CopyOp::SHALLOW_COPY); + + META_Object(osgDirectShow, DirectShowImageStream); + void run(); + bool openFile(const std::string& file); + bool openCaptureDevices(); + void setOptions(const Options& map); + void play(); + void pause(); + void rewind(); + osg::ImageStream::StreamStatus getStatus(); + void seek(double time); + double getLength() const; + double getFrameRate() const; + void setTimeMultiplier(double rate); + double getTimeMultiplier() const; + void quit(bool /*waitForThreadToExit*/ = true); + void stop(); +}; + + +//----------------------------------------------------------------------------- +// CTextureRenderer Class Declarations +//----------------------------------------------------------------------------- +class CTextureRenderer : public CBaseVideoRenderer, public osg::Referenced +{ +public: + IGraphBuilder* _graphBuilder; // GraphBuilder + IMediaControl* _mediaControl; // Media Control + IMediaSeeking* _mediaSeeking; // Media seeking + IMediaEvent* _mediaEvent; // Media Event + IBaseFilter* _videoCaptureDevice; + IBaseFilter* _fileSource; + IBaseFilter* _soundOutputDevice; + IBaseFilter* _soundCaptureDevice; + HRESULT _dropFrame; + + CTextureRenderer(DirectShowImageStream* imageStream, HRESULT* valid); + ~CTextureRenderer(); + + void setFilename(const std::string& filename); + bool initBuildGraph(); + bool initCaptureDevice(); + bool openCaptureDevices(const DirectShowImageStream::Options& options); + bool openVideoCaptureDevice(const std::string& capture, int wantWidth, int wantHeight, double wantFps); + bool openSoundCaptureDevice(const std::string& capture, int nbChannels = 2); + + + bool openFile(const std::string& file); + bool startGraph(); + void syncStreams(bool state); + bool setupOutputSoundDevice(ICreateDevEnum* devs); + void releaseRessources(); + IGraphBuilder* getGraphBuilder() { return _graphBuilder; } + + HRESULT ShouldDrawSampleNow(IMediaSample *sample, REFERENCE_TIME *start, REFERENCE_TIME *stop); + bool StopFilters(); + + HRESULT CheckMediaType(const CMediaType *pmt ); // Format acceptable? + HRESULT SetMediaType(const CMediaType *pmt ); // Video format notification + HRESULT DoRenderSample(IMediaSample *pMediaSample); // New video sample + + int _width; + int _height; + int _pitch; + std::string _videoCaptureDeviceName; + std::string _soundCaptureDeviceName; + std::string _soundOutputDeviceName; + std::string _filename; + const std::string& getVideoCaptureDeviceName() const { return _videoCaptureDeviceName; } + const std::string& getSoundOutputDeviceName() const { return _soundOutputDeviceName; } + const std::string& getSoundCaptureDeviceName() const { return _soundCaptureDeviceName; } + const std::string& getFilename() const { return _filename; } + osg::observer_ptr _imageStream; +}; + +#endif diff --git a/src/osgPlugins/directshow/DirectShowTexture.cpp b/src/osgPlugins/directshow/DirectShowTexture.cpp new file mode 100644 index 000000000..90953fe71 --- /dev/null +++ b/src/osgPlugins/directshow/DirectShowTexture.cpp @@ -0,0 +1,1872 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 2009 Tharsis Software + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library 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 + * OpenSceneGraph Public License for more details. + * + * Authors: + * Cedric Pinson +*/ + +#include "DirectShowTexture" +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +HRESULT GetPin(IBaseFilter* pFilter, LPCWSTR pName, IPin** ppPin); +HRESULT GetPin(IBaseFilter* pFilter, const GUID* pFormat, PIN_DIRECTION PinDir, IPin** ppPin); + + +struct NamedGuid +{ + const GUID *pguid; + const TCHAR *psz; +}; + +// 73646976-0000-0010-8000-00AA00389B71 'vids' == WMMEDIATYPE_Video +EXTERN_GUID(WMMEDIATYPE_Video, +0x73646976, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); +// 73647561-0000-0010-8000-00AA00389B71 'auds' == WMMEDIATYPE_Audio +EXTERN_GUID(WMMEDIATYPE_Audio, +0x73647561, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); +// 73636d64-0000-0010-8000-00AA00389B71 'scmd' == MEDIATYPE_Script +EXTERN_GUID(WMMEDIATYPE_Script, +0x73636d64, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); +// 34A50FD8-8AA5-4386-81FE-A0EFE0488E31 WMMEDIATYPE_Image +EXTERN_GUID(WMMEDIATYPE_Image, +0x34a50fd8, 0x8aa5, 0x4386, 0x81, 0xfe, 0xa0, 0xef, 0xe0, 0x48, 0x8e, 0x31); +// D9E47579-930E-4427-ADFC-AD80F290E470 'fxfr' == WMMEDIATYPE_FileTransfer +EXTERN_GUID(WMMEDIATYPE_FileTransfer, +0xd9e47579, 0x930e, 0x4427, 0xad, 0xfc, 0xad, 0x80, 0xf2, 0x90, 0xe4, 0x70); +// 9BBA1EA7-5AB2-4829-BA57-0940209BCF3E 'text' == WMMEDIATYPE_Text +EXTERN_GUID(WMMEDIATYPE_Text, +0x9bba1ea7, 0x5ab2, 0x4829, 0xba, 0x57, 0x9, 0x40, 0x20, 0x9b, 0xcf, 0x3e); + +// 00000000-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_Base +EXTERN_GUID(WMMEDIASUBTYPE_Base, +0x00000000, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); +// e436eb78-524f-11ce-9f53-0020af0ba770 MEDIASUBTYPE_RGB1 +EXTERN_GUID(WMMEDIASUBTYPE_RGB1, +0xe436eb78, 0x524f, 0x11ce, 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70); +// e436eb79-524f-11ce-9f53-0020af0ba770 MEDIASUBTYPE_RGB4 +EXTERN_GUID(WMMEDIASUBTYPE_RGB4, +0xe436eb79, 0x524f, 0x11ce, 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70); +// e436eb7a-524f-11ce-9f53-0020af0ba770 MEDIASUBTYPE_RGB8 +EXTERN_GUID(WMMEDIASUBTYPE_RGB8, +0xe436eb7a, 0x524f, 0x11ce, 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70); +// e436eb7b-524f-11ce-9f53-0020af0ba770 MEDIASUBTYPE_RGB565 +EXTERN_GUID(WMMEDIASUBTYPE_RGB565, +0xe436eb7b, 0x524f, 0x11ce, 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70); +// e436eb7c-524f-11ce-9f53-0020af0ba770 MEDIASUBTYPE_RGB555 +EXTERN_GUID(WMMEDIASUBTYPE_RGB555, +0xe436eb7c, 0x524f, 0x11ce, 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70); +// e436eb7d-524f-11ce-9f53-0020af0ba770 MEDIASUBTYPE_RGB24 +EXTERN_GUID(WMMEDIASUBTYPE_RGB24, +0xe436eb7d, 0x524f, 0x11ce, 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70); +// e436eb7e-524f-11ce-9f53-0020af0ba770 MEDIASUBTYPE_RGB32 +EXTERN_GUID(WMMEDIASUBTYPE_RGB32, +0xe436eb7e, 0x524f, 0x11ce, 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70); +// 30323449-0000-0010-8000-00AA00389B71 'YV12' == MEDIASUBTYPE_I420 +EXTERN_GUID(WMMEDIASUBTYPE_I420, +0x30323449, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); +// 56555949-0000-0010-8000-00AA00389B71 'YV12' == MEDIASUBTYPE_IYUV +EXTERN_GUID(WMMEDIASUBTYPE_IYUV, +0x56555949, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); +// 31313259-0000-0010-8000-00AA00389B71 'YV12' == MEDIASUBTYPE_YV12 +EXTERN_GUID(WMMEDIASUBTYPE_YV12, +0x32315659, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); +// 32595559-0000-0010-8000-00AA00389B71 'YUY2' == MEDIASUBTYPE_YUY2 +EXTERN_GUID(WMMEDIASUBTYPE_YUY2, +0x32595559, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); +// 59565955-0000-0010-8000-00AA00389B71 'UYVY' == MEDIASUBTYPE_UYVY +EXTERN_GUID(WMMEDIASUBTYPE_UYVY, +0x59565955, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); +// 55595659-0000-0010-8000-00AA00389B71 'YVYU' == MEDIASUBTYPE_YVYU +EXTERN_GUID(WMMEDIASUBTYPE_YVYU, +0x55595659, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); +// 39555659-0000-0010-8000-00AA00389B71 'YVU9' == MEDIASUBTYPE_YVU9 +EXTERN_GUID(WMMEDIASUBTYPE_YVU9, +0x39555659, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); +// 3334504D-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_MP43 +EXTERN_GUID(WMMEDIASUBTYPE_MP43, +0x3334504D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); +// 5334504D-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_MP4S +EXTERN_GUID(WMMEDIASUBTYPE_MP4S, +0x5334504D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); +// 31564D57-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_WMV1 +EXTERN_GUID(WMMEDIASUBTYPE_WMV1, +0x31564D57, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); +// 32564D57-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_WMV2 +EXTERN_GUID(WMMEDIASUBTYPE_WMV2, +0x32564D57, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); +// 3153534D-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_MSS1 +EXTERN_GUID(WMMEDIASUBTYPE_MSS1, +0x3153534D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); +// e06d8026-db46-11cf-b4d1-00805f6cbbea WMMEDIASUBTYPE_MPEG2_VIDEO +EXTERN_GUID(WMMEDIASUBTYPE_MPEG2_VIDEO, +0xe06d8026, 0xdb46, 0x11cf, 0xb4, 0xd1, 0x00, 0x80, 0x5f, 0x6c, 0xbb, 0xea); +// 00000001-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_PCM +EXTERN_GUID(WMMEDIASUBTYPE_PCM, +0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); +// 00000009-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_DRM +EXTERN_GUID(WMMEDIASUBTYPE_DRM, +0x00000009, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); +// 00000162-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_WMAudioV9 +EXTERN_GUID(WMMEDIASUBTYPE_WMAudioV9, +0x00000162, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); +// 00000163-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_WMAudio_Lossless +EXTERN_GUID(WMMEDIASUBTYPE_WMAudio_Lossless, +0x00000163, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); +// 3253534D-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_MSS2 +EXTERN_GUID(WMMEDIASUBTYPE_MSS2, +0x3253534D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); +// 0000000A-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_WMSP1 +EXTERN_GUID( WMMEDIASUBTYPE_WMSP1, +0x0000000A,0x0000,0x0010,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71); +// 33564D57-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_WMV3 +EXTERN_GUID(WMMEDIASUBTYPE_WMV3, +0x33564D57, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); +// 00000161-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_WMAudioV8 +EXTERN_GUID(WMMEDIASUBTYPE_WMAudioV8, +0x00000161, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); +// 00000161-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_WMAudioV7 +EXTERN_GUID(WMMEDIASUBTYPE_WMAudioV7, +0x00000161, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); +// 00000161-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_WMAudioV2 +EXTERN_GUID(WMMEDIASUBTYPE_WMAudioV2, +0x00000161, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); +// 00000130-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_ACELPnet +EXTERN_GUID(WMMEDIASUBTYPE_ACELPnet, +0x00000130, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); +// 00000050-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_MP3 +EXTERN_GUID(WMMEDIASUBTYPE_MP3, +0x00000055, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); +// 776257d4-c627-41cb-8f81-7ac7ff1c40cc WMMEDIASUBTYPE_WebStream +EXTERN_GUID(WMMEDIASUBTYPE_WebStream, +0x776257d4, 0xc627, 0x41cb, 0x8f, 0x81, 0x7a, 0xc7, 0xff, 0x1c, 0x40, 0xcc); + +// 05589f80-c356-11ce-bf01-00aa0055595a WMFORMAT_VideoInfo +EXTERN_GUID(WMFORMAT_VideoInfo, +0x05589f80, 0xc356, 0x11ce, 0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a); +// 05589f81-c356-11ce-bf01-00aa0055595a WMFORMAT_WaveFormatEx +EXTERN_GUID(WMFORMAT_WaveFormatEx, +0x05589f81, 0xc356, 0x11ce, 0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a); +// 5C8510F2-DEBE-4ca7-BBA5-F07A104F8DFF WMFORMAT_Script +EXTERN_GUID(WMFORMAT_Script, +0x5c8510f2, 0xdebe, 0x4ca7, 0xbb, 0xa5, 0xf0, 0x7a, 0x10, 0x4f, 0x8d, 0xff); + +// 82f38a70-c29f-11d1-97ad-00a0c95ea850 WMSCRIPTTYPE_TwoStrings +EXTERN_GUID( WMSCRIPTTYPE_TwoStrings, +0x82f38a70,0xc29f,0x11d1,0x97,0xad,0x00,0xa0,0xc9,0x5e,0xa8,0x50); + +// e06d80e3-db46-11cf-b4d1-00805f6cbbea WMFORMAT_MPEG2Video +EXTERN_GUID(WMFORMAT_MPEG2Video, +0xe06d80e3, 0xdb46, 0x11cf, 0xb4, 0xd1, 0x00, 0x80, 0x05f, 0x6c, 0xbb, 0xea); + +EXTERN_GUID( CLSID_WMMUTEX_Language, 0xD6E22A00,0x35DA,0x11D1,0x90,0x34,0x00,0xA0,0xC9,0x03,0x49,0xBE ); +EXTERN_GUID( CLSID_WMMUTEX_Bitrate, 0xD6E22A01,0x35DA,0x11D1,0x90,0x34,0x00,0xA0,0xC9,0x03,0x49,0xBE ); +EXTERN_GUID( CLSID_WMMUTEX_Presentation, 0xD6E22A02,0x35DA,0x11D1,0x90,0x34,0x00,0xA0,0xC9,0x03,0x49,0xBE ); +EXTERN_GUID( CLSID_WMMUTEX_Unknown, 0xD6E22A03,0x35DA,0x11D1,0x90,0x34,0x00,0xA0,0xC9,0x03,0x49,0xBE ); +EXTERN_GUID( CLSID_WMBandwidthSharing_Exclusive, 0xaf6060aa,0x5197,0x11d2,0xb6,0xaf,0x00,0xc0,0x4f,0xd9,0x08,0xe9 ); +EXTERN_GUID( CLSID_WMBandwidthSharing_Partial, 0xaf6060ab,0x5197,0x11d2,0xb6,0xaf,0x00,0xc0,0x4f,0xd9,0x08,0xe9 ); + +const NamedGuid MediaType[]= +{ + {&MEDIASUBTYPE_AIFF, TEXT("AIFF\0")}, + {&MEDIASUBTYPE_AU, TEXT("AU\0")}, + {&MEDIASUBTYPE_AnalogVideo_NTSC_M, TEXT("AnalogVideo_NTSC_M\0")}, + {&MEDIASUBTYPE_AnalogVideo_PAL_B, TEXT("AnalogVideo_PAL_B\0")}, + {&MEDIASUBTYPE_AnalogVideo_PAL_D, TEXT("AnalogVideo_PAL_D\0")}, + {&MEDIASUBTYPE_AnalogVideo_PAL_G, TEXT("AnalogVideo_PAL_G\0")}, + {&MEDIASUBTYPE_AnalogVideo_PAL_H, TEXT("AnalogVideo_PAL_H\0")}, + {&MEDIASUBTYPE_AnalogVideo_PAL_I, TEXT("AnalogVideo_PAL_I\0")}, + {&MEDIASUBTYPE_AnalogVideo_PAL_M, TEXT("AnalogVideo_PAL_M\0")}, + {&MEDIASUBTYPE_AnalogVideo_PAL_N, TEXT("AnalogVideo_PAL_N\0")}, + {&MEDIASUBTYPE_AnalogVideo_SECAM_B, TEXT("AnalogVideo_SECAM_B\0")}, + {&MEDIASUBTYPE_AnalogVideo_SECAM_D, TEXT("AnalogVideo_SECAM_D\0")}, + {&MEDIASUBTYPE_AnalogVideo_SECAM_G, TEXT("AnalogVideo_SECAM_G\0")}, + {&MEDIASUBTYPE_AnalogVideo_SECAM_H, TEXT("AnalogVideo_SECAM_H\0")}, + {&MEDIASUBTYPE_AnalogVideo_SECAM_K, TEXT("AnalogVideo_SECAM_K\0")}, + {&MEDIASUBTYPE_AnalogVideo_SECAM_K1, TEXT("AnalogVideo_SECAM_K1\0")}, + {&MEDIASUBTYPE_AnalogVideo_SECAM_L, TEXT("AnalogVideo_SECAM_L\0")}, + + {&MEDIASUBTYPE_ARGB1555, TEXT("ARGB1555\0")}, + {&MEDIASUBTYPE_ARGB4444, TEXT("ARGB4444\0")}, + {&MEDIASUBTYPE_ARGB32, TEXT("ARGB32\0")}, + {&MEDIASUBTYPE_A2R10G10B10, TEXT("A2R10G10B10\0")}, + {&MEDIASUBTYPE_A2B10G10R10, TEXT("A2B10G10R10\0")}, + + {&MEDIASUBTYPE_AYUV, TEXT("AYUV\0")}, + {&MEDIASUBTYPE_AI44, TEXT("AI44\0")}, + {&MEDIASUBTYPE_IA44, TEXT("IA44\0")}, + {&MEDIASUBTYPE_NV12, TEXT("NV12\0")}, + {&MEDIASUBTYPE_IMC1, TEXT("IMC1\0")}, + {&MEDIASUBTYPE_IMC2, TEXT("IMC2\0")}, + {&MEDIASUBTYPE_IMC3, TEXT("IMC3\0")}, + {&MEDIASUBTYPE_IMC4, TEXT("IMC4\0")}, + + {&MEDIASUBTYPE_Asf, TEXT("Asf\0")}, + {&MEDIASUBTYPE_Avi, TEXT("Avi\0")}, + {&MEDIASUBTYPE_CFCC, TEXT("CFCC\0")}, + {&MEDIASUBTYPE_CLJR, TEXT("CLJR\0")}, + {&MEDIASUBTYPE_CPLA, TEXT("CPLA\0")}, + {&MEDIASUBTYPE_CLPL, TEXT("CLPL\0")}, + {&MEDIASUBTYPE_DOLBY_AC3, TEXT("DOLBY_AC3\0")}, + {&MEDIASUBTYPE_DOLBY_AC3_SPDIF, TEXT("DOLBY_AC3_SPDIF\0")}, + {&MEDIASUBTYPE_DVCS, TEXT("DVCS\0")}, + {&MEDIASUBTYPE_DVD_LPCM_AUDIO, TEXT("DVD_LPCM_AUDIO\0")}, + {&MEDIASUBTYPE_DVD_NAVIGATION_DSI, TEXT("DVD_NAVIGATION_DSI\0")}, + {&MEDIASUBTYPE_DVD_NAVIGATION_PCI, TEXT("DVD_NAVIGATION_PCI\0")}, + {&MEDIASUBTYPE_DVD_NAVIGATION_PROVIDER, TEXT("DVD_NAVIGATION_PROVIDER\0")}, + {&MEDIASUBTYPE_DVD_SUBPICTURE, TEXT("DVD_SUBPICTURE\0")}, + {&MEDIASUBTYPE_DVSD, TEXT("DVSD\0")}, + {&MEDIASUBTYPE_DRM_Audio, TEXT("DRM_Audio\0")}, + {&MEDIASUBTYPE_DssAudio, TEXT("DssAudio\0")}, + {&MEDIASUBTYPE_DssVideo, TEXT("DssVideo\0")}, + {&MEDIASUBTYPE_IF09, TEXT("IF09\0")}, + {&MEDIASUBTYPE_IEEE_FLOAT, TEXT("IEEE_FLOAT\0")}, + {&MEDIASUBTYPE_IJPG, TEXT("IJPG\0")}, + {&MEDIASUBTYPE_IYUV, TEXT("IYUV\0")}, + {&MEDIASUBTYPE_Line21_BytePair, TEXT("Line21_BytePair\0")}, + {&MEDIASUBTYPE_Line21_GOPPacket, TEXT("Line21_GOPPacket\0")}, + {&MEDIASUBTYPE_Line21_VBIRawData, TEXT("Line21_VBIRawData\0")}, + {&MEDIASUBTYPE_MDVF, TEXT("MDVF\0")}, + {&MEDIASUBTYPE_MJPG, TEXT("MJPG\0")}, + {&MEDIASUBTYPE_MPEG1Audio, TEXT("MPEG1Audio\0")}, + {&MEDIASUBTYPE_MPEG1AudioPayload, TEXT("MPEG1AudioPayload\0")}, + {&MEDIASUBTYPE_MPEG1Packet, TEXT("MPEG1Packet\0")}, + {&MEDIASUBTYPE_MPEG1Payload, TEXT("MPEG1Payload\0")}, + {&MEDIASUBTYPE_MPEG1System, TEXT("MPEG1System\0")}, + {&MEDIASUBTYPE_MPEG1Video, TEXT("MPEG1Video\0")}, + {&MEDIASUBTYPE_MPEG1VideoCD, TEXT("MPEG1VideoCD\0")}, + {&MEDIASUBTYPE_MPEG2_AUDIO, TEXT("MPEG2_AUDIO\0")}, + {&MEDIASUBTYPE_MPEG2_PROGRAM, TEXT("MPEG2_PROGRAM\0")}, + {&MEDIASUBTYPE_MPEG2_TRANSPORT, TEXT("MPEG2_TRANSPORT\0")}, + {&MEDIASUBTYPE_MPEG2_VIDEO, TEXT("MPEG2_VIDEO\0")}, + {&MEDIASUBTYPE_None, TEXT("None\0")}, + {&MEDIASUBTYPE_Overlay, TEXT("Overlay\0")}, + {&MEDIASUBTYPE_PCM, TEXT("PCM\0")}, + {&MEDIASUBTYPE_PCMAudio_Obsolete, TEXT("PCMAudio_Obsolete\0")}, + {&MEDIASUBTYPE_Plum, TEXT("Plum\0")}, + {&MEDIASUBTYPE_QTJpeg, TEXT("QTJpeg\0")}, + {&MEDIASUBTYPE_QTMovie, TEXT("QTMovie\0")}, + {&MEDIASUBTYPE_QTRle, TEXT("QTRle\0")}, + {&MEDIASUBTYPE_QTRpza, TEXT("QTRpza\0")}, + {&MEDIASUBTYPE_QTSmc, TEXT("QTSmc\0")}, + {&MEDIASUBTYPE_RAW_SPORT, TEXT("RAW_SPORT\0")}, + {&MEDIASUBTYPE_RGB1, TEXT("RGB1\0")}, + {&MEDIASUBTYPE_RGB24, TEXT("RGB24\0")}, + {&MEDIASUBTYPE_RGB32, TEXT("RGB32\0")}, + {&MEDIASUBTYPE_RGB4, TEXT("RGB4\0")}, + {&MEDIASUBTYPE_RGB555, TEXT("RGB555\0")}, + {&MEDIASUBTYPE_RGB565, TEXT("RGB565\0")}, + {&MEDIASUBTYPE_RGB8, TEXT("RGB8\0")}, + {&MEDIASUBTYPE_SPDIF_TAG_241h, TEXT("SPDIF_TAG_241h\0")}, + {&MEDIASUBTYPE_TELETEXT, TEXT("TELETEXT\0")}, + {&MEDIASUBTYPE_TVMJ, TEXT("TVMJ\0")}, + {&MEDIASUBTYPE_UYVY, TEXT("UYVY\0")}, + {&MEDIASUBTYPE_VPVBI, TEXT("VPVBI\0")}, + {&MEDIASUBTYPE_VPVideo, TEXT("VPVideo\0")}, + {&MEDIASUBTYPE_WAKE, TEXT("WAKE\0")}, + {&MEDIASUBTYPE_WAVE, TEXT("WAVE\0")}, + {&MEDIASUBTYPE_Y211, TEXT("Y211\0")}, + {&MEDIASUBTYPE_Y411, TEXT("Y411\0")}, + {&MEDIASUBTYPE_Y41P, TEXT("Y41P\0")}, + {&MEDIASUBTYPE_YUY2, TEXT("YUY2\0")}, + {&MEDIASUBTYPE_YV12, TEXT("YV12\0")}, + {&MEDIASUBTYPE_YVU9, TEXT("YVU9\0")}, + {&MEDIASUBTYPE_YVYU, TEXT("YVYU\0")}, + {&MEDIASUBTYPE_YUYV, TEXT("YUYV\0")}, + {&MEDIASUBTYPE_dvhd, TEXT("dvhd\0")}, + {&MEDIASUBTYPE_dvsd, TEXT("dvsd\0")}, + {&MEDIASUBTYPE_dvsl, TEXT("dvsl\0")}, + + {&MEDIATYPE_AUXLine21Data, TEXT("AUXLine21Data\0")}, + {&MEDIATYPE_AnalogAudio, TEXT("AnalogAudio\0")}, + {&MEDIATYPE_AnalogVideo, TEXT("AnalogVideo\0")}, + {&MEDIATYPE_Audio, TEXT("Audio\0")}, + {&MEDIATYPE_DVD_ENCRYPTED_PACK, TEXT("DVD_ENCRYPTED_PACK\0")}, + {&MEDIATYPE_DVD_NAVIGATION, TEXT("DVD_NAVIGATION\0")}, + {&MEDIATYPE_File, TEXT("File\0")}, + {&MEDIATYPE_Interleaved, TEXT("Interleaved\0")}, + {&MEDIATYPE_LMRT, TEXT("LMRT\0")}, + {&MEDIATYPE_MPEG1SystemStream, TEXT("MPEG1SystemStream\0")}, + {&MEDIATYPE_MPEG2_PES, TEXT("MPEG2_PES\0")}, + {&MEDIATYPE_Midi, TEXT("Midi\0")}, + {&MEDIATYPE_ScriptCommand, TEXT("ScriptCommand\0")}, + {&MEDIATYPE_Stream, TEXT("Stream\0")}, + {&MEDIATYPE_Text, TEXT("Text\0")}, + {&MEDIATYPE_Timecode, TEXT("Timecode\0")}, + {&MEDIATYPE_URL_STREAM, TEXT("URL_STREAM\0")}, + {&MEDIATYPE_VBI, TEXT("VBI\0")}, + {&MEDIATYPE_Video, TEXT("Video\0")}, + + {&WMMEDIATYPE_Audio, TEXT("WMMEDIATYPE_Audio\0")}, + {&WMMEDIATYPE_Video, TEXT("WMMEDIATYPE_Video\0")}, + {&WMMEDIATYPE_Script, TEXT("WMMEDIATYPE_Script\0")}, + {&WMMEDIATYPE_Image, TEXT("WMMEDIATYPE_Image\0")}, + {&WMMEDIATYPE_FileTransfer, TEXT("WMMEDIATYPE_FileTransfer\0")}, + {&WMMEDIATYPE_Text, TEXT("WMMEDIATYPE_Text\0")}, + + {&WMMEDIASUBTYPE_Base, TEXT("WMMEDIASUBTYPE_Base\0")}, + {&WMMEDIASUBTYPE_RGB1, TEXT("WMMEDIASUBTYPE_RGB1\0")}, + {&WMMEDIASUBTYPE_RGB4, TEXT("WMMEDIASUBTYPE_RGB4\0")}, + {&WMMEDIASUBTYPE_RGB8, TEXT("WMMEDIASUBTYPE_RGB8\0")}, + {&WMMEDIASUBTYPE_RGB565, TEXT("WMMEDIASUBTYPE_RGB565\0")}, + {&WMMEDIASUBTYPE_RGB555, TEXT("WMMEDIASUBTYPE_RGB555\0")}, + {&WMMEDIASUBTYPE_RGB24, TEXT("WMMEDIASUBTYPE_RGB24\0")}, + {&WMMEDIASUBTYPE_RGB32, TEXT("WMMEDIASUBTYPE_RGB32\0")}, + {&WMMEDIASUBTYPE_I420, TEXT("WMMEDIASUBTYPE_I420\0")}, + {&WMMEDIASUBTYPE_IYUV, TEXT("WMMEDIASUBTYPE_IYUV\0")}, + {&WMMEDIASUBTYPE_YV12, TEXT("WMMEDIASUBTYPE_YV12\0")}, + {&WMMEDIASUBTYPE_YUY2, TEXT("WMMEDIASUBTYPE_YUY2\0")}, + {&WMMEDIASUBTYPE_UYVY, TEXT("WMMEDIASUBTYPE_UYVY\0")}, + {&WMMEDIASUBTYPE_YVYU, TEXT("WMMEDIASUBTYPE_YVYU\0")}, + {&WMMEDIASUBTYPE_YVU9, TEXT("WMMEDIASUBTYPE_YVU9\0")}, + {&WMMEDIASUBTYPE_MP43, TEXT("WMMEDIASUBTYPE_MP43\0")}, + {&WMMEDIASUBTYPE_MP4S, TEXT("WMMEDIASUBTYPE_MP4S\0")}, + + {&WMMEDIASUBTYPE_WMV1, TEXT("WMMEDIASUBTYPE_WMV1\0")}, + {&WMMEDIASUBTYPE_WMV2, TEXT("WMMEDIASUBTYPE_WMV2\0")}, + {&WMMEDIASUBTYPE_WMV3, TEXT("WMMEDIASUBTYPE_WMV3\0")}, + {&WMMEDIASUBTYPE_MSS1, TEXT("WMMEDIASUBTYPE_MSS1\0")}, + {&WMMEDIASUBTYPE_MSS2, TEXT("WMMEDIASUBTYPE_MSS2\0")}, + {&WMMEDIASUBTYPE_MPEG2_VIDEO, TEXT("WMMEDIASUBTYPE_MPEG2_VIDEO\0")}, + {&WMMEDIASUBTYPE_PCM, TEXT("WMMEDIASUBTYPE_PCM\0")}, + {&WMMEDIASUBTYPE_DRM, TEXT("WMMEDIASUBTYPE_DRM\0")}, + {&WMMEDIASUBTYPE_WMAudioV9, TEXT("WMMEDIASUBTYPE_WMAudioV9\0")}, + {&WMMEDIASUBTYPE_WMAudio_Lossless, TEXT("WMMEDIASUBTYPE_WMAudio_Lossless\0")}, + {&WMMEDIASUBTYPE_WMAudioV8, TEXT("WMMEDIASUBTYPE_WMAudioV8\0")}, + {&WMMEDIASUBTYPE_WMAudioV7, TEXT("WMMEDIASUBTYPE_WMAudioV7\0")}, + {&WMMEDIASUBTYPE_WMAudioV2, TEXT("WMMEDIASUBTYPE_WMAudioV2\0")}, + {&WMMEDIASUBTYPE_ACELPnet, TEXT("WMMEDIASUBTYPE_ACELPnet\0")}, + {&WMMEDIASUBTYPE_WMSP1, TEXT("WMMEDIASUBTYPE_WMSP1\0")}, + + {&WMFORMAT_VideoInfo, TEXT("WMFORMAT_VideoInfo\0")}, + {&WMFORMAT_WaveFormatEx, TEXT("WMFORMAT_WaveFormatEx\0")}, + {&WMFORMAT_Script, TEXT("WMFORMAT_Script\0")}, + {&WMFORMAT_MPEG2Video, TEXT("WMFORMAT_MPEG2Video\0")}, + + {&WMSCRIPTTYPE_TwoStrings, TEXT("WMSCRIPTTYPE_TwoStrings\0")}, + + {&PIN_CATEGORY_ANALOGVIDEOIN, TEXT("PIN_CATEGORY_ANALOGVIDEOIN\0")}, + {&PIN_CATEGORY_CAPTURE, TEXT("PIN_CATEGORY_CAPTURE\0")}, + {&PIN_CATEGORY_CC, TEXT("PIN_CATEGORY_CC\0")}, + {&PIN_CATEGORY_EDS, TEXT("PIN_CATEGORY_EDS\0")}, + {&PIN_CATEGORY_NABTS, TEXT("PIN_CATEGORY_NABTS\0")}, + {&PIN_CATEGORY_PREVIEW, TEXT("PIN_CATEGORY_PREVIEW\0")}, + {&PIN_CATEGORY_STILL, TEXT("PIN_CATEGORY_STILL\0")}, + {&PIN_CATEGORY_TELETEXT, TEXT("PIN_CATEGORY_TELETEXT\0")}, + {&PIN_CATEGORY_TIMECODE, TEXT("PIN_CATEGORY_TIMECODE\0")}, + {&PIN_CATEGORY_VBI, TEXT("PIN_CATEGORY_VBI\0")}, + {&PIN_CATEGORY_VIDEOPORT, TEXT("PIN_CATEGORY_VIDEOPORT\0")}, + {&PIN_CATEGORY_VIDEOPORT_VBI, TEXT("PIN_CATEGORY_VIDEOPORT_VBI\0")}, + + {&CLSID_ACMWrapper, TEXT("CLSID_ACMWrapper\0")}, + {&CLSID_AVICo, TEXT("CLSID_AVICo\0")}, + {&CLSID_AVIDec, TEXT("CLSID_AVIDec\0")}, + {&CLSID_AVIDoc, TEXT("CLSID_AVIDoc\0")}, + {&CLSID_AVIDraw, TEXT("CLSID_AVIDraw\0")}, + {&CLSID_AVIMIDIRender, TEXT("CLSID_AVIMIDIRender\0")}, + {&CLSID_ActiveMovieCategories, TEXT("CLSID_ActiveMovieCategories\0")}, + {&CLSID_AnalogVideoDecoderPropertyPage, TEXT("CLSID_AnalogVideoDecoderPropertyPage\0")}, + {&CLSID_WMAsfReader, TEXT("CLSID_WMAsfReader\0")}, + {&CLSID_WMAsfWriter, TEXT("CLSID_WMAsfWriter\0")}, + {&CLSID_AsyncReader, TEXT("CLSID_AsyncReader\0")}, + {&CLSID_AudioCompressorCategory, TEXT("CLSID_AudioCompressorCategory\0")}, + {&CLSID_AudioInputDeviceCategory, TEXT("CLSID_AudioInputDeviceCategory\0")}, + {&CLSID_AudioProperties, TEXT("CLSID_AudioProperties\0")}, + {&CLSID_AudioRecord, TEXT("CLSID_AudioRecord\0")}, + {&CLSID_AudioRender, TEXT("CLSID_AudioRender\0")}, + {&CLSID_AudioRendererCategory, TEXT("CLSID_AudioRendererCategory\0")}, + {&CLSID_AviDest, TEXT("CLSID_AviDest\0")}, + {&CLSID_AviMuxProptyPage, TEXT("CLSID_AviMuxProptyPage\0")}, + {&CLSID_AviMuxProptyPage1, TEXT("CLSID_AviMuxProptyPage1\0")}, + {&CLSID_AviReader, TEXT("CLSID_AviReader\0")}, + {&CLSID_AviSplitter, TEXT("CLSID_AviSplitter\0")}, + {&CLSID_CAcmCoClassManager, TEXT("CLSID_CAcmCoClassManager\0")}, + {&CLSID_CDeviceMoniker, TEXT("CLSID_CDeviceMoniker\0")}, + {&CLSID_CIcmCoClassManager, TEXT("CLSID_CIcmCoClassManager\0")}, + {&CLSID_CMidiOutClassManager, TEXT("CLSID_CMidiOutClassManager\0")}, + {&CLSID_CMpegAudioCodec, TEXT("CLSID_CMpegAudioCodec\0")}, + {&CLSID_CMpegVideoCodec, TEXT("CLSID_CMpegVideoCodec\0")}, + {&CLSID_CQzFilterClassManager, TEXT("CLSID_CQzFilterClassManager\0")}, + {&CLSID_CVidCapClassManager, TEXT("CLSID_CVidCapClassManager\0")}, + {&CLSID_CWaveOutClassManager, TEXT("CLSID_CWaveOutClassManager\0")}, + {&CLSID_CWaveinClassManager, TEXT("CLSID_CWaveinClassManager\0")}, + {&CLSID_CameraControlPropertyPage, TEXT("CLSID_CameraControlPropertyPage\0")}, + {&CLSID_CaptureGraphBuilder, TEXT("CLSID_CaptureGraphBuilder\0")}, + {&CLSID_CaptureProperties, TEXT("CLSID_CaptureProperties\0")}, + {&CLSID_Colour, TEXT("CLSID_Colour\0")}, + {&CLSID_CrossbarFilterPropertyPage, TEXT("CLSID_CrossbarFilterPropertyPage\0")}, + {&CLSID_DSoundRender, TEXT("CLSID_DSoundRender\0")}, + {&CLSID_DVDHWDecodersCategory, TEXT("CLSID_DVDHWDecodersCategory\0")}, + {&CLSID_DVDNavigator, TEXT("CLSID_DVDNavigator\0")}, + {&CLSID_DVDecPropertiesPage, TEXT("CLSID_DVDecPropertiesPage\0")}, + {&CLSID_DVEncPropertiesPage, TEXT("CLSID_DVEncPropertiesPage\0")}, + {&CLSID_DVMux, TEXT("CLSID_DVMux\0")}, + {&CLSID_DVMuxPropertyPage, TEXT("CLSID_DVMuxPropertyPage\0")}, + {&CLSID_DVSplitter, TEXT("CLSID_DVSplitter\0")}, + {&CLSID_DVVideoCodec, TEXT("CLSID_DVVideoCodec\0")}, + {&CLSID_DVVideoEnc, TEXT("CLSID_DVVideoEnc\0")}, + {&CLSID_DirectDraw, TEXT("CLSID_DirectDraw\0")}, + {&CLSID_DirectDrawClipper, TEXT("CLSID_DirectDrawClipper\0")}, + {&CLSID_DirectDrawProperties, TEXT("CLSID_DirectDrawProperties\0")}, + {&CLSID_Dither, TEXT("CLSID_Dither\0")}, + {&CLSID_DvdGraphBuilder, TEXT("CLSID_DvdGraphBuilder\0")}, + {&CLSID_FGControl, TEXT("CLSID_FGControl\0")}, + {&CLSID_FileSource, TEXT("CLSID_FileSource\0")}, + {&CLSID_FileWriter, TEXT("CLSID_FileWriter\0")}, + {&CLSID_FilterGraph, TEXT("CLSID_FilterGraph\0")}, + {&CLSID_FilterGraphNoThread, TEXT("CLSID_FilterGraphNoThread\0")}, + {&CLSID_FilterMapper, TEXT("CLSID_FilterMapper\0")}, + {&CLSID_FilterMapper2, TEXT("CLSID_FilterMapper2\0")}, + {&CLSID_InfTee, TEXT("CLSID_InfTee\0")}, + {&CLSID_LegacyAmFilterCategory, TEXT("CLSID_LegacyAmFilterCategory\0")}, + {&CLSID_Line21Decoder, TEXT("CLSID_Line21Decoder\0")}, + {&CLSID_MOVReader, TEXT("CLSID_MOVReader\0")}, + {&CLSID_MPEG1Doc, TEXT("CLSID_MPEG1Doc\0")}, + {&CLSID_MPEG1PacketPlayer, TEXT("CLSID_MPEG1PacketPlayer\0")}, + {&CLSID_MPEG1Splitter, TEXT("CLSID_MPEG1Splitter\0")}, + {&CLSID_MediaPropertyBag, TEXT("CLSID_MediaPropertyBag\0")}, + {&CLSID_MemoryAllocator, TEXT("CLSID_MemoryAllocator\0")}, + {&CLSID_MidiRendererCategory, TEXT("CLSID_MidiRendererCategory\0")}, + {&CLSID_ModexProperties, TEXT("CLSID_ModexProperties\0")}, + {&CLSID_ModexRenderer, TEXT("CLSID_ModexRenderer\0")}, + {&CLSID_OverlayMixer, TEXT("CLSID_OverlayMixer\0")}, + {&CLSID_PerformanceProperties, TEXT("CLSID_PerformanceProperties\0")}, + {&CLSID_PersistMonikerPID, TEXT("CLSID_PersistMonikerPID\0")}, + {&CLSID_ProtoFilterGraph, TEXT("CLSID_ProtoFilterGraph\0")}, + {&CLSID_QualityProperties, TEXT("CLSID_QualityProperties\0")}, + {&CLSID_SeekingPassThru, TEXT("CLSID_SeekingPassThru\0")}, + {&CLSID_SmartTee, TEXT("CLSID_SmartTee\0")}, + {&CLSID_SystemClock, TEXT("CLSID_SystemClock\0")}, + {&CLSID_SystemDeviceEnum, TEXT("CLSID_SystemDeviceEnum\0")}, + {&CLSID_TVAudioFilterPropertyPage, TEXT("CLSID_TVAudioFilterPropertyPage\0")}, + {&CLSID_TVTunerFilterPropertyPage, TEXT("CLSID_TVTunerFilterPropertyPage\0")}, + {&CLSID_TextRender, TEXT("CLSID_TextRender\0")}, + {&CLSID_URLReader, TEXT("CLSID_URLReader\0")}, + {&CLSID_VBISurfaces, TEXT("CLSID_VBISurfaces\0")}, + {&CLSID_VPObject, TEXT("CLSID_VPObject\0")}, + {&CLSID_VPVBIObject, TEXT("CLSID_VPVBIObject\0")}, + {&CLSID_VfwCapture, TEXT("CLSID_VfwCapture\0")}, + {&CLSID_VideoCompressorCategory, TEXT("CLSID_VideoCompressorCategory\0")}, + {&CLSID_VideoInputDeviceCategory, TEXT("CLSID_VideoInputDeviceCategory\0")}, + {&CLSID_VideoProcAmpPropertyPage, TEXT("CLSID_VideoProcAmpPropertyPage\0")}, + {&CLSID_VideoRenderer, TEXT("CLSID_VideoRenderer\0")}, + {&CLSID_VideoStreamConfigPropertyPage, TEXT("CLSID_VideoStreamConfigPropertyPage\0")}, + + {&CLSID_WMMUTEX_Language, TEXT("CLSID_WMMUTEX_Language\0")}, + {&CLSID_WMMUTEX_Bitrate, TEXT("CLSID_WMMUTEX_Bitrate\0")}, + {&CLSID_WMMUTEX_Presentation, TEXT("CLSID_WMMUTEX_Presentation\0")}, + {&CLSID_WMMUTEX_Unknown, TEXT("CLSID_WMMUTEX_Unknown\0")}, + + {&CLSID_WMBandwidthSharing_Exclusive, TEXT("CLSID_WMBandwidthSharing_Exclusive\0")}, + {&CLSID_WMBandwidthSharing_Partial, TEXT("CLSID_WMBandwidthSharing_Partial\0")}, + + {&FORMAT_AnalogVideo, TEXT("FORMAT_AnalogVideo\0")}, + {&FORMAT_DVD_LPCMAudio, TEXT("FORMAT_DVD_LPCMAudio\0")}, + {&FORMAT_DolbyAC3, TEXT("FORMAT_DolbyAC3\0")}, + {&FORMAT_DvInfo, TEXT("FORMAT_DvInfo\0")}, + {&FORMAT_MPEG2Audio, TEXT("FORMAT_MPEG2Audio\0")}, + {&FORMAT_MPEG2Video, TEXT("FORMAT_MPEG2Video\0")}, + {&FORMAT_MPEG2_VIDEO, TEXT("FORMAT_MPEG2_VIDEO\0")}, + {&FORMAT_MPEGStreams, TEXT("FORMAT_MPEGStreams\0")}, + {&FORMAT_MPEGVideo, TEXT("FORMAT_MPEGVideo\0")}, + {&FORMAT_None, TEXT("FORMAT_None\0")}, + {&FORMAT_VIDEOINFO2, TEXT("FORMAT_VIDEOINFO2\0")}, + {&FORMAT_VideoInfo, TEXT("FORMAT_VideoInfo\0")}, + {&FORMAT_VideoInfo2, TEXT("FORMAT_VideoInfo2\0")}, + {&FORMAT_WaveFormatEx, TEXT("FORMAT_WaveFormatEx\0")}, + + {&TIME_FORMAT_BYTE, TEXT("TIME_FORMAT_BYTE\0")}, + {&TIME_FORMAT_FIELD, TEXT("TIME_FORMAT_FIELD\0")}, + {&TIME_FORMAT_FRAME, TEXT("TIME_FORMAT_FRAME\0")}, + {&TIME_FORMAT_MEDIA_TIME, TEXT("TIME_FORMAT_MEDIA_TIME\0")}, + {&TIME_FORMAT_SAMPLE, TEXT("TIME_FORMAT_SAMPLE\0")}, + + {&ROPSETID_Pin, TEXT("AMPROPSETID_Pin\0")}, + {&AM_INTERFACESETID_Standard, TEXT("AM_INTERFACESETID_Standard\0")}, + {&AM_KSCATEGORY_AUDIO, TEXT("AM_KSCATEGORY_AUDIO\0")}, + {&AM_KSCATEGORY_CAPTURE, TEXT("AM_KSCATEGORY_CAPTURE\0")}, + {&AM_KSCATEGORY_CROSSBAR, TEXT("AM_KSCATEGORY_CROSSBAR\0")}, + {&AM_KSCATEGORY_DATACOMPRESSOR, TEXT("AM_KSCATEGORY_DATACOMPRESSOR\0")}, + {&AM_KSCATEGORY_RENDER, TEXT("AM_KSCATEGORY_RENDER\0")}, + {&AM_KSCATEGORY_TVAUDIO, TEXT("AM_KSCATEGORY_TVAUDIO\0")}, + {&AM_KSCATEGORY_TVTUNER, TEXT("AM_KSCATEGORY_TVTUNER\0")}, + {&AM_KSCATEGORY_VIDEO, TEXT("AM_KSCATEGORY_VIDEO\0")}, + {&AM_KSPROPSETID_AC3, TEXT("AM_KSPROPSETID_AC3\0")}, + {&AM_KSPROPSETID_CopyProt, TEXT("AM_KSPROPSETID_CopyProt\0")}, + {&AM_KSPROPSETID_DvdSubPic, TEXT("AM_KSPROPSETID_DvdSubPic\0")}, + {&AM_KSPROPSETID_TSRateChange, TEXT("AM_KSPROPSETID_TSRateChange\0")}, + + {&IID_IAMDirectSound, TEXT("IID_IAMDirectSound\0")}, + {&IID_IAMLine21Decoder, TEXT("IID_IAMLine21Decoder\0")}, + {&IID_IBaseVideoMixer, TEXT("IID_IBaseVideoMixer\0")}, + {&IID_IDDVideoPortContainer, TEXT("IID_IDDVideoPortContainer\0")}, + {&IID_IDirectDraw, TEXT("IID_IDirectDraw\0")}, + {&IID_IDirectDraw2, TEXT("IID_IDirectDraw2\0")}, + {&IID_IDirectDrawClipper, TEXT("IID_IDirectDrawClipper\0")}, + {&IID_IDirectDrawColorControl, TEXT("IID_IDirectDrawColorControl\0")}, + {&IID_IDirectDrawKernel, TEXT("IID_IDirectDrawKernel\0")}, + {&IID_IDirectDrawPalette, TEXT("IID_IDirectDrawPalette\0")}, + {&IID_IDirectDrawSurface, TEXT("IID_IDirectDrawSurface\0")}, + {&IID_IDirectDrawSurface2, TEXT("IID_IDirectDrawSurface2\0")}, + {&IID_IDirectDrawSurface3, TEXT("IID_IDirectDrawSurface3\0")}, + {&IID_IDirectDrawSurfaceKernel, TEXT("IID_IDirectDrawSurfaceKernel\0")}, + {&IID_IDirectDrawVideo, TEXT("IID_IDirectDrawVideo\0")}, + {&IID_IFullScreenVideo, TEXT("IID_IFullScreenVideo\0")}, + {&IID_IFullScreenVideoEx, TEXT("IID_IFullScreenVideoEx\0")}, + {&IID_IKsDataTypeHandler, TEXT("IID_IKsDataTypeHandler\0")}, + {&IID_IKsInterfaceHandler, TEXT("IID_IKsInterfaceHandler\0")}, + {&IID_IKsPin, TEXT("IID_IKsPin\0")}, + {&IID_IMixerPinConfig, TEXT("IID_IMixerPinConfig\0")}, + {&IID_IMixerPinConfig2, TEXT("IID_IMixerPinConfig2\0")}, + {&IID_IMpegAudioDecoder, TEXT("IID_IMpegAudioDecoder\0")}, + {&IID_IQualProp, TEXT("IID_IQualProp\0")}, + {&IID_IVPConfig, TEXT("IID_IVPConfig\0")}, + {&IID_IVPControl, TEXT("IID_IVPControl\0")}, + {&IID_IVPNotify, TEXT("IID_IVPNotify\0")}, + {&IID_IVPNotify2, TEXT("IID_IVPNotify2\0")}, + {&IID_IVPObject, TEXT("IID_IVPObject\0")}, + {&IID_IVPVBIConfig, TEXT("IID_IVPVBIConfig\0")}, + {&IID_IVPVBINotify, TEXT("IID_IVPVBINotify\0")}, + {&IID_IVPVBIObject, TEXT("IID_IVPVBIObject\0")}, + + {&LOOK_DOWNSTREAM_ONLY, TEXT("LOOK_DOWNSTREAM_ONLY\0")}, + {&LOOK_UPSTREAM_ONLY, TEXT("LOOK_UPSTREAM_ONLY\0")}, + {0, 0}, +}; + +//----------------------------------------------------------------------------- +// GetPin +// Find the pin of the specified format type on the given filter +// This method leaves an outstanding reference on the pin if successful +HRESULT GetPin(IBaseFilter* pFilter, const GUID* pFormat, PIN_DIRECTION PinDir, IPin** ppPin) +{ + HRESULT hr = S_OK; + + if (pFilter && pFormat && ppPin) + { + IEnumPins* pIEnumPins = NULL; + hr = pFilter->EnumPins(&pIEnumPins); + if (SUCCEEDED(hr)) + { + // find the pin with the specified format + IPin* pIPin = NULL; + while (S_OK == pIEnumPins->Next(1, &pIPin, NULL)) + { + // match the pin direction + PIN_DIRECTION pinDir; + pIPin->QueryDirection(&pinDir); + if (pinDir == PinDir) + { + // match pin direction check the first media type returned from the upstream pin + IEnumMediaTypes* pIEnumMT = NULL; + hr = pIPin->EnumMediaTypes(&pIEnumMT); + if (SUCCEEDED(hr)) + { + AM_MEDIA_TYPE* pmt = NULL; + hr = pIEnumMT->Next(1, &pmt, NULL); + if (S_OK == hr) + { + if (pmt->majortype == *pFormat) + { + // found the pin with the specified format + *ppPin = pIPin; + DeleteMediaType(pmt); + break; + } + else + { + DeleteMediaType(pmt); + } + } + pIEnumMT->Release(); + } + } + if (pIPin) pIPin->Release(); pIPin = 0; + } + + if (NULL == *ppPin) + { + // failed to find the named pin + hr = E_FAIL; + } + pIEnumPins->Release(); + } + } + else + { + hr = E_INVALIDARG; + } + + return hr; +} +//----------------------------------------------------------------------------- +// GetPin +// Find the pin of the specified name on the given filter +// This method leaves an outstanding reference on the pin if successful +HRESULT GetPin(IBaseFilter* pFilter, LPCWSTR pName, IPin** ppPin) +{ + HRESULT hr = S_OK; + + if (pFilter && pName && ppPin) + { + IEnumPins* pIEnumPins = NULL; + hr = pFilter->EnumPins(&pIEnumPins); + if (SUCCEEDED(hr)) + { + IPin* pIPin = NULL; + while (S_OK == pIEnumPins->Next(1, &pIPin, NULL)) + { + PIN_INFO info = {0}; + hr = pIPin->QueryPinInfo(&info); + if (SUCCEEDED(hr)) + { + if (info.pFilter) info.pFilter->Release(); info.pFilter = 0; + + if (0 == wcsncmp(info.achName, pName, wcslen(pName))) + { + // matched the pin category + *ppPin = pIPin; + break; + } + } + if (pIPin) pIPin->Release(); pIPin = 0; + } + pIEnumPins->Release(); + } + + if (NULL == *ppPin) + { + // failed to find the named pin + hr = E_FAIL; + } + } + else + { + hr = E_INVALIDARG; + } + + return hr; +} + +//----------------------------------------------------------------------------- +// FindPinInterface +// Attempt to locate the interface on the pin with the specified format or on the first pin if no +// format is provided. +HRESULT FindPinInterface(IBaseFilter* pFilter, const GUID* pFormat, PIN_DIRECTION PinDir, const IID& riid, void** ppvInterface) +{ + HRESULT hr = S_OK; + + if (pFilter && ppvInterface) + { + IPin* pIPin = NULL; + if (pFormat) + { + hr = GetPin(pFilter, pFormat, PinDir, &pIPin); + } + else + { + IEnumPins* pIEnumPins = NULL; + hr = pFilter->EnumPins(&pIEnumPins); + if (SUCCEEDED(hr)) + { + hr = pIEnumPins->Next(1, &pIPin, NULL); + } + pIEnumPins->Release(); + } + + if (SUCCEEDED(hr)) + { + hr = pIPin->QueryInterface(riid, ppvInterface); + } + pIPin->Release(); + } + else + { + hr = E_INVALIDARG; + } + + return hr; +} + +std::string getStringFromGUID(const GUID *pGUID) +{ + int i=0; + // Find format GUID's name in the named guids table + while (MediaType[i].pguid != 0) + { + if(*pGUID == *(MediaType[i].pguid)) + { + return std::string(MediaType[i].psz); + } + i++; + } + + // return the guid if does not recognize the type + const int maxChar = 60; + LPOLESTR pwszClsid = (LPOLESTR) CoTaskMemAlloc(maxChar*2); + CHAR szCLSID[maxChar]; + int nchar = StringFromGUID2(*pGUID, pwszClsid, maxChar); + // Convert result to ANSI + WideCharToMultiByte(CP_ACP, 0, pwszClsid, -1, szCLSID, nchar, NULL, NULL); + CoTaskMemFree(pwszClsid); + return std::string(szCLSID); +} +const GUID* getGUIDFromString(const std::string& str) +{ + int i=0; + // Find format GUID's name in the named guids table + while (MediaType[i].pguid != 0) + { + if(str == std::string((MediaType[i].psz))) + return MediaType[i].pguid; + i++; + } + return 0; +} +static std::string getErrorMessage(HRESULT hr) +{ + if (FAILED(hr)) + { + TCHAR szErr[MAX_ERROR_TEXT_LEN]; + DWORD res = AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN); + if (res == 0) + { + StringCchPrintf(szErr, MAX_ERROR_TEXT_LEN, "Unknown Error: 0x%2x", hr); + } + return std::string (szErr); + } + return std::string(""); +} + +static bool checkError(const std::string& prefix, HRESULT hr) +{ + if (FAILED(hr)) + osg::notify(osg::WARN) << prefix << " " << getErrorMessage(hr) << std::endl; + + if (hr == E_ABORT) + return false; + if (hr == E_FAIL) + return false; + if (hr == E_OUTOFMEMORY) + return false; + if (hr == E_POINTER) + return false; + if (hr == VFW_E_CANNOT_CONNECT) + return false; + if (hr == 0x80040256) + return false; + if (hr == 0x80040216) + return false; + + return true; +} + +bool CTextureRenderer::initBuildGraph() +{ + std::string prefixForMessage; + { + std::stringstream ss; + ss << _imageStream.get(); + prefixForMessage = ss.str(); + } + + HRESULT hr; + hr = CoCreateInstance( CLSID_FilterGraph, 0, CLSCTX_INPROC,IID_IGraphBuilder, (void **)&_graphBuilder ); + if (!checkError(prefixForMessage, hr)) + return false; + + hr = _graphBuilder->QueryInterface( IID_IMediaControl, (void **)&_mediaControl ); + if (!checkError(prefixForMessage, hr)) + return false; + + hr = _graphBuilder->QueryInterface( IID_IMediaSeeking, (void **)&_mediaSeeking ); + if (!checkError(prefixForMessage, hr)) + return false; + + hr = _graphBuilder->AddFilter((IBaseFilter*)this, L"Sampler"); + if (!checkError(prefixForMessage, hr)) + return false; + return true; +} + + +struct ListDeviceAvailable +{ + struct DeviceEntry + { + std::string _name; + std::string _clsid; + IMoniker* _device; + DeviceEntry(const std::string& name = "" , const std::string& clsid = "", IMoniker* device = 0) : _name(name), _clsid(clsid), _device(device) {} + }; + std::vector _listDevice; + IEnumMoniker* _enumMoniker; + ListDeviceAvailable(IEnumMoniker *enumMoniker) : _enumMoniker(enumMoniker) + { + createList(); + } + ~ListDeviceAvailable() + { + for (int i = 0; i < (int)_listDevice.size(); i++) + if (_listDevice[i]._device) + _listDevice[i]._device->Release(); + } + + void displayDevicesFound(const std::string& prefixForMessage, osg::NotifySeverity serverity = osg::NOTICE) const + { + for (int i = 0; i < (int)_listDevice.size(); i++) + osg::notify(serverity) << prefixForMessage << " device \"" << _listDevice[i]._name << "\" clsid " << _listDevice[i]._clsid << std::endl; + } + + DeviceEntry getDevice(const std::string& name) + { + for (int i = 0; i < (int)_listDevice.size(); i++) + if (_listDevice[i]._name == name) + return _listDevice[i]; + //if (!_listDevice.empty()) + // return _listDevice.front(); + return DeviceEntry(); + } + + void createList() + { + IMoniker *device = NULL; + HRESULT hr; + // Enumerate all items associated with the moniker + while (_enumMoniker->Next(1, &device, NULL) == S_OK) + { + IPropertyBag *pPropBag = NULL; + CLSID clsidFilter; + + VARIANT varName; + VARIANT varFilterClsid; + + VariantInit(&varName); + VariantInit(&varFilterClsid); + + // Associate moniker with a file + hr = device->BindToStorage(0, 0, IID_IPropertyBag, + (void **)&pPropBag); + + // Read filter name from property bag + if (SUCCEEDED(hr)) + { + hr = pPropBag->Read(L"FriendlyName", &varName, 0); + } + + // Read filter's CLSID from property bag. This CLSID string will be + // converted to a binary CLSID and passed to AddFilter(), which will + // add the filter's name to the listbox and its CLSID to the listbox + // item's DataPtr item. When the user clicks on a filter name in + // the listbox, we'll read the stored CLSID, convert it to a string, + // and use it to find the filter's filename in the registry. + + if (SUCCEEDED(hr)) + { + // Read CLSID string from property bag + hr = pPropBag->Read(L"CLSID", &varFilterClsid, 0); + + // Add filter name and CLSID to listbox + if (SUCCEEDED(hr)) + { + hr = CLSIDFromString(varFilterClsid.bstrVal, &clsidFilter); + } + else if (hr == E_PROP_ID_UNSUPPORTED) + { + clsidFilter = GUID_NULL; // No CLSID is listed. + hr = S_OK; + } + } + + // covert to std::string + _bstr_t bstr_t(varName.bstrVal); + std::string deviceName(bstr_t); + std::string deviceGUID; + + // Add filter name and filename to list + if(SUCCEEDED(hr)) + { + LPOLESTR pwszClsid; + CHAR szCLSID[60]; + hr = StringFromCLSID(clsidFilter, &pwszClsid); + if (!FAILED(hr)) + { + // Convert result to ANSI + WideCharToMultiByte(CP_ACP, 0, pwszClsid, -1, szCLSID, 60, NULL, NULL); + //osg::notify(osg::NOTICE) << "device \"" << truename << "\" id " << szCLSID << std::endl; + deviceGUID = std::string(szCLSID); + } + CoTaskMemFree(pwszClsid); + } + + VariantClear(&varName); + VariantClear(&varFilterClsid); + + // Cleanup interfaces + if (pPropBag) pPropBag->Release(); + + _listDevice.push_back(DeviceEntry(deviceName, deviceGUID, device)); + } + } + + +}; + + +struct ListCapDeviceAvailable +{ + typedef std::pair CapEntry; + std::vector _capsList; + IAMStreamConfig* _config; + ListCapDeviceAvailable(IAMStreamConfig* config) : _config(config) + { + createList(); + } + ~ListCapDeviceAvailable() + { + for (int i = 0; i < (int)_capsList.size(); i++) + if (_capsList[i].first) + DeleteMediaType(_capsList[i].first); + } + + void displayCapsFound(const std::string& prefixForMessage = "") const + { + for (int i = 0; i < (int)_capsList.size(); i++) + { + VIDEOINFOHEADER* video= _capsList[i].second; + displayCap(video, prefixForMessage); + } + } + + static void displayCap(VIDEOINFOHEADER* video, const std::string& prefix = "") + { + if (!video) + return; + double fps = 1.0/ (video->AvgTimePerFrame * 100.0 * 1e-9); + FOURCCMap fccMap(video->bmiHeader.biCompression); + GUID g1 = (GUID)fccMap; + osg::notify(osg::NOTICE) << prefix << " cap " << video->bmiHeader.biWidth << " x " << video->bmiHeader.biHeight << " bit per pixel " << video->bmiHeader.biBitCount << " (" << getStringFromGUID(&g1) << ") at " << fps << " fps" << std::endl; + } + + std::pair getCaps(int width, int height, double fps) + { + std::vector filterResolution; + for (int i = 0; i < (int)_capsList.size(); i++) + { + VIDEOINFOHEADER* video= _capsList[i].second; + if (video->bmiHeader.biWidth == width && video->bmiHeader.biHeight == height) + { + filterResolution.push_back(_capsList[i]); + } + } + // get the max fps if the fps are not reach on the desired resolution + typedef std::multimap ContainerFrameRateSorted; + ContainerFrameRateSorted filterFrameRate; + for (int i = 0; i < (int)filterResolution.size(); i++) + { + VIDEOINFOHEADER* video= filterResolution[i].second; + double capfps = 1.0/ (video->AvgTimePerFrame * 100.0 * 1e-9); + double error = fabs(capfps - fps); + filterFrameRate.insert(std::pair(error, filterResolution[i])); + } + + CapEntry best = CapEntry(0,0); + CapEntry first = CapEntry(0,0); + for (ContainerFrameRateSorted::iterator it = filterFrameRate.begin(); + it != filterFrameRate.end(); + ++it) + { + if (first == CapEntry(0,0)) + first = it->second; + + if (it->first < 1e-3) + { + VIDEOINFOHEADER* video= it->second.second; + FOURCCMap fccMap(video->bmiHeader.biCompression); + GUID g1 = (GUID)fccMap; + if (getStringFromGUID(&g1) == std::string("YUY2")) + best = it->second; + } + } + if (best != CapEntry(0,0)) + return best; + if (first != CapEntry(0,0)) + return first; + + if (!_capsList.empty()) + return _capsList.front(); + return CapEntry(0,0); + } + + void createList() + { + std::string device = "capture"; + // Use the IPin to get the interface: + + // get the number of formats and make sure the strutucre size matches + int iCount, iSize; + VIDEO_STREAM_CONFIG_CAPS caps; + _config->GetNumberOfCapabilities(&iCount, &iSize); + if( sizeof(caps) != iSize ) + return; + + // now go through all formats and use the one you like + for(int i=0; i < iCount; i++) + { + // GetStreamCaps allocats the AM_MEDIA_TYPE, which must be deleted by using DeleteMediaType + AM_MEDIA_TYPE *pmt = NULL; + if( _config->GetStreamCaps(i, &pmt, (BYTE*)&caps) == S_OK ) + { + if (pmt->formattype == FORMAT_VideoInfo && pmt->cbFormat >= sizeof(VIDEOINFOHEADER)) + { + VIDEOINFOHEADER *video= + reinterpret_cast(pmt->pbFormat); + _capsList.push_back(CapEntry(pmt, video)); + } + else + { + DeleteMediaType(pmt); + } + } + } + } +}; + + +bool CTextureRenderer::setupOutputSoundDevice(ICreateDevEnum* devs) +{ + if (!devs) + return false; + + std::string prefixForMessage; + { + std::stringstream ss; + ss << _imageStream.get(); + prefixForMessage = ss.str(); + } + + HRESULT hr; + std::string outputdevice = "Default DirectSound Device"; + IEnumMoniker* audioRenderer = 0; hr = devs?devs->CreateClassEnumerator (CLSID_AudioRendererCategory, &audioRenderer, 0):0; + if (!checkError(prefixForMessage, hr)) + return false; + ListDeviceAvailable deviceFinder(audioRenderer); + + deviceFinder.displayDevicesFound(prefixForMessage + " sounddevice", osg::INFO); + + ListDeviceAvailable::DeviceEntry device = deviceFinder.getDevice(outputdevice); + if (!device._device) + { + osg::notify(osg::WARN) << prefixForMessage << " no output sound device \"" << outputdevice << "\" found" << std::endl; + return false; + } + + _soundOutputDeviceName = device._name; + IMoniker* mon = device._device; + hr = mon?mon->BindToObject(0,0,IID_IBaseFilter, (void**)&_soundOutputDevice):0; + checkError(prefixForMessage, hr); + if (FAILED(hr)) + return false; + + hr = _graphBuilder->AddFilter(_soundOutputDevice,NULL); + checkError(prefixForMessage, hr); + if (FAILED(hr)) + { + if (_soundOutputDevice) _soundOutputDevice->Release(); _soundOutputDevice = 0; + return false; + } + return true; +} + +bool CTextureRenderer::openVideoCaptureDevice(const std::string& capture, int wantWidth, int wantHeight, double wantFps) +{ + std::string prefixForMessage; + { + std::stringstream ss; + ss << _imageStream.get(); + prefixForMessage = ss.str(); + } + + HRESULT hr; + ICreateDevEnum* devs = 0; hr = CoCreateInstance (CLSID_SystemDeviceEnum, 0, CLSCTX_INPROC, IID_ICreateDevEnum, (void **) &devs); + if (!checkError(prefixForMessage, hr)) + return false; + + IEnumMoniker* cams = 0; hr = devs?devs->CreateClassEnumerator (CLSID_VideoInputDeviceCategory, &cams, 0):0; + if (!checkError(prefixForMessage, hr)) + return false; + + ListDeviceAvailable deviceFinder(cams); + { + std::stringstream ss; + ss << std::hex << _imageStream.get() << " capture"; + deviceFinder.displayDevicesFound(ss.str(), osg::INFO); + } + ListDeviceAvailable::DeviceEntry device = deviceFinder.getDevice(capture); + + if (!device._device) + { + osg::notify(osg::WARN) << _imageStream.get() << " no capture device \"" << capture << "\" found" << std::endl; + return false; + } + _videoCaptureDeviceName = device._name; + osg::notify(osg::NOTICE) << _imageStream.get() << " use capture device \"" << getVideoCaptureDeviceName() << "\"" << std::endl; + + { + std::stringstream ss; + ss << _imageStream.get() << " \"" << getVideoCaptureDeviceName() << "\""; + prefixForMessage = ss.str(); + } + + + IMoniker* mon = device._device; + + hr = mon?mon->BindToObject(0,0,IID_IBaseFilter, (void**)&_videoCaptureDevice):0; + if (!checkError(prefixForMessage, hr)) + return false; + + IEnumPins* pins = 0; hr = _videoCaptureDevice?_videoCaptureDevice->EnumPins(&pins):0; + if (!checkError(prefixForMessage, hr)) + return false; + + IPin* cap = 0; hr = pins?pins->Next(1,&cap, 0):0; + if (pins) pins->Release(); pins = 0; + if (!checkError(prefixForMessage, hr)) + return false; + + + IAMStreamConfig* capConfig = 0; hr = cap->QueryInterface( IID_IAMStreamConfig, (void **)&capConfig); + if (capConfig) + { + ListCapDeviceAvailable capsDevice(capConfig); + capsDevice.displayCapsFound(prefixForMessage); + ListCapDeviceAvailable::CapEntry found = capsDevice.getCaps(wantWidth, wantHeight, wantFps); + if (found.first) + { + ListCapDeviceAvailable::displayCap(found.second, prefixForMessage + " use "); + capConfig->SetFormat(found.first); + } + capConfig->Release(); + } + + hr = _graphBuilder->AddFilter(_videoCaptureDevice, L"Capture Source"); + if (!checkError(prefixForMessage, hr)) + return false; + + IPin* rnd = 0; + hr = FindPin(L"In", &rnd); + if (!checkError(prefixForMessage, hr)) + return false; + + hr = _graphBuilder->Connect(cap,rnd); + + if (rnd) rnd->Release(); + if (cap) cap->Release(); + + bool result = checkError(prefixForMessage, hr); + return result; +} + + +bool CTextureRenderer::openSoundCaptureDevice(const std::string& capture, int nbChannels) +{ + std::string prefixForMessage; + { + std::stringstream ss; + ss << _imageStream.get(); + prefixForMessage = ss.str(); + } + + HRESULT hr; + ICreateDevEnum* devs = 0; hr = CoCreateInstance (CLSID_SystemDeviceEnum, 0, CLSCTX_INPROC, IID_ICreateDevEnum, (void **) &devs); + if (!checkError(prefixForMessage, hr)) + return false; + + IEnumMoniker* captureDevices = 0; hr = devs?devs->CreateClassEnumerator (CLSID_AudioInputDeviceCategory, &captureDevices, 0):0; + if (!checkError(prefixForMessage, hr)) + return false; + + ListDeviceAvailable deviceFinder(captureDevices); + { + std::stringstream ss; + ss << std::hex << _imageStream.get() << " capture sound "; + deviceFinder.displayDevicesFound(ss.str(), osg::INFO); + } + ListDeviceAvailable::DeviceEntry device = deviceFinder.getDevice(capture); + + if (!device._device) + { + osg::notify(osg::WARN) << _imageStream.get() << " no sound capture device \"" << capture << "\" found" << std::endl; + return false; + } + _soundCaptureDeviceName = device._name; + osg::notify(osg::NOTICE) << _imageStream.get() << " use sound capture device \"" << getSoundCaptureDeviceName() << "\"" << std::endl; + + { + std::stringstream ss; + ss << _imageStream.get() << " \"" << getSoundCaptureDeviceName() << "\""; + prefixForMessage = ss.str(); + } + + + IMoniker* mon = device._device; + + hr = mon?mon->BindToObject(0,0,IID_IBaseFilter, (void**)&_soundCaptureDevice):0; + if (FAILED(hr)) + { + checkError(prefixForMessage, hr); + return false; + } + + IAMStreamConfig* pISC = NULL; + hr = FindPinInterface(_soundCaptureDevice, &MEDIATYPE_Audio, PINDIR_OUTPUT, IID_IAMStreamConfig, reinterpret_cast(&pISC)); + if (FAILED(hr)) + { + checkError(prefixForMessage, hr); + return false; + } + // loop through all the capabilities (audio formats) and populate the control + int count, size; + hr = pISC->GetNumberOfCapabilities(&count, &size); + if (SUCCEEDED(hr)) + { + if (sizeof(AUDIO_STREAM_CONFIG_CAPS) == size) + { + AM_MEDIA_TYPE* pmt = NULL; + AUDIO_STREAM_CONFIG_CAPS ascc; + WAVEFORMATEX* pwfex = NULL; + + for (int index=0; indexGetStreamCaps(index, &pmt, reinterpret_cast(&ascc)); + if (SUCCEEDED(hr)) + { + TCHAR buffer[32]; + + ZeroMemory(buffer, sizeof(buffer)); + + pwfex = (WAVEFORMATEX*)pmt->pbFormat; + + // provide a useful description of the formats + if (1 == pwfex->nChannels) + { + StringCbPrintf(buffer, sizeof(buffer), TEXT("%d channel, %2.1fkHz, %d-bit"), (int)pwfex->nChannels, (float)pwfex->nSamplesPerSec / 1000, (int)pwfex->wBitsPerSample); + } + else + { + StringCbPrintf(buffer, sizeof(buffer), TEXT("%d channels, %2.1fkHz, %d-bit"), (int)pwfex->nChannels, (float)pwfex->nSamplesPerSec / 1000, (int)pwfex->wBitsPerSample); + } + + // set default format + if (pwfex->nChannels == nbChannels) + { + pISC->SetFormat(pmt); + osg::notify(osg::NOTICE) << prefixForMessage << " use format " << buffer << std::endl; + break; + } else + osg::notify(osg::NOTICE) << prefixForMessage << buffer << std::endl; + + } + } + } + else + { + osg::notify(osg::WARN) << prefixForMessage << " can t retrieve informations pins" << std::endl; + } + } + if (pISC) pISC->Release(); pISC = 0; + IPin* captureOutputDevicePinOut = 0; hr = _soundCaptureDevice? ::GetPin(_soundCaptureDevice,L"Capture",&captureOutputDevicePinOut) : 0; + if (FAILED(hr)) { + checkError(prefixForMessage, hr); + return false; + } + + hr = _graphBuilder->AddFilter(_soundCaptureDevice, L"Sound Capture Source"); + if (FAILED(hr)) + { + checkError(prefixForMessage, hr); + return false; + } + + if (!setupOutputSoundDevice(devs)) + { + devs->Release(); devs = 0; + if (captureOutputDevicePinOut) captureOutputDevicePinOut->Release(); captureOutputDevicePinOut = 0; + return false; + } + devs->Release(); devs = 0; + + std::string prefixForMessageSound; + { + std::stringstream ss; + ss << _imageStream.get() << " " << getSoundOutputDeviceName(); + prefixForMessageSound = ss.str(); + } + + IPin* soundOutputDevicePinIn = 0; + hr = _soundOutputDevice->FindPin(L"Audio Input pin (rendered)", &soundOutputDevicePinIn); + if (FAILED(hr)) + { + checkError(prefixForMessageSound, hr); + if (soundOutputDevicePinIn) soundOutputDevicePinIn->Release(); soundOutputDevicePinIn = 0; + if (captureOutputDevicePinOut) captureOutputDevicePinOut->Release(); captureOutputDevicePinOut = 0; + return false; + } + + hr = _graphBuilder->Connect(captureOutputDevicePinOut, soundOutputDevicePinIn); + + if (soundOutputDevicePinIn) soundOutputDevicePinIn->Release(); soundOutputDevicePinIn = 0; + if (captureOutputDevicePinOut) captureOutputDevicePinOut->Release(); captureOutputDevicePinOut = 0; + + if (FAILED(hr)) + { + checkError(prefixForMessageSound, hr); + return false; + } + + return true; +} + + +bool CTextureRenderer::openCaptureDevices(const DirectShowImageStream::Options& o) +{ + std::string prefixForMessage; + { + std::stringstream ss; + ss << _imageStream.get(); + prefixForMessage = ss.str(); + } + + DirectShowImageStream::Options options = o; + syncStreams(false); + + for (DirectShowImageStream::Options::iterator it = options.begin(); it != options.end(); it++) + osg::notify(osg::NOTICE) << prefixForMessage << " option " << it->first << " = " << it->second << std::endl; + + std::string soundCaptureDevice = options["captureSoundDevice"]; + std::string videoCaptureDevice = options["captureVideoDevice"]; + + osg::notify(osg::NOTICE) << prefixForMessage << " try to open video capture device " << videoCaptureDevice; + if (!soundCaptureDevice .empty()) + osg::notify(osg::NOTICE) << " and sound capture device " << soundCaptureDevice ; + osg::notify(osg::NOTICE) << std::endl; + + if (!initBuildGraph()) + return false; + + int wantWidth = atoi(options["captureWantedWidth"].c_str()); + int wantHeight = atoi(options["captureWantedHeight"].c_str()); + float wantFps = atof(options["captureWantedFps"].c_str()); + if (!openVideoCaptureDevice(videoCaptureDevice, wantWidth, wantHeight, wantFps)) + return false; + + if (!soundCaptureDevice.empty() && !openSoundCaptureDevice(soundCaptureDevice )) + osg::notify(osg::WARN) << prefixForMessage << " failed to setup sound capture device " << soundCaptureDevice << std::endl; + + return true; +} + + +bool CTextureRenderer::openFile(const std::string& file) +{ + syncStreams(true); + WCHAR wFileName[MAX_PATH]; + wFileName[MAX_PATH-1] = 0; // NULL-terminate + if (file.empty()) + return false; + + _filename = file; + std::string prefixForMessage; + { + std::stringstream ss; + ss << _imageStream.get() << " " << getFilename(); + prefixForMessage = ss.str(); + } + + const char *ansistr = file.c_str(); + int lenA = lstrlenA(ansistr); + int lenW; + BSTR unicodestr; + + lenW = ::MultiByteToWideChar(CP_ACP, 0, ansistr, lenA, 0, 0); + if (lenW > 0) + { + // Check whether conversion was successful + unicodestr = ::SysAllocStringLen(0, lenW); + ::MultiByteToWideChar(CP_ACP, 0, ansistr, lenA, unicodestr, lenW); + } + + (void)StringCchCopyW(wFileName, NUMELMS(wFileName), unicodestr); + + // when done, free the BSTR + ::SysFreeString(unicodestr); + + HRESULT hr; + if (!initBuildGraph()) + return false; + + IPin* videoOutputPin = 0; + + std::string lowercase = file; + std::transform(lowercase.begin(), lowercase.end(), lowercase.begin(), tolower); + if (lowercase.rfind(".wmv") != std::string::npos) + { + hr = _graphBuilder->AddSourceFilter(wFileName, L"Windows Media source filter", &_fileSource); + if (!checkError(prefixForMessage, hr)) + return false; + hr = _fileSource?_fileSource->FindPin(L"Raw Video 1", &videoOutputPin):0; + } + else + { + hr = _graphBuilder->AddSourceFilter(wFileName, L"File Source", &_fileSource); + if (!checkError(prefixForMessage, hr)) + return false; + hr = _fileSource?_fileSource->FindPin(L"Output", &videoOutputPin):0; + } + + if (!checkError(prefixForMessage, hr)) + return false; + + IPin* rnd = 0; + hr = FindPin(L"In", &rnd); + if (!checkError(prefixForMessage, hr)) + return false; + + hr = _graphBuilder->Connect(videoOutputPin, rnd); + if (videoOutputPin) videoOutputPin->Release(); videoOutputPin = 0; + + if (rnd) rnd->Release(); rnd = 0; + if (!checkError(prefixForMessage, hr)) + return false; + + + if (lowercase.rfind(".avi") == std::string::npos) // not an avi, dont try to connect sounds + return true; + + // check if we find the sounds output pin on the streams + IBaseFilter* AVISpliterFilter = 0; + hr = _graphBuilder->FindFilterByName(L"AVI Splitter", &AVISpliterFilter); + if (FAILED(hr)) + osg::notify(osg::WARN) << prefixForMessage << " did not find AVI SPlitter to connect sound, " << getErrorMessage(hr) << std::endl; + + if (AVISpliterFilter) + { + IPin* soundStreamPinOut = 0; + hr = AVISpliterFilter->FindPin(L"Stream 01",&soundStreamPinOut); + AVISpliterFilter->Release(); AVISpliterFilter = 0; + + if (FAILED(hr)) + osg::notify(osg::WARN) << prefixForMessage << " can't find Stream 01 pin on AVIS Splitter, maybe the flux does have sound, " << getErrorMessage(hr) << std::endl; + + if (soundStreamPinOut) + { + // connect sounds to graph + ICreateDevEnum* devs = 0; hr = CoCreateInstance (CLSID_SystemDeviceEnum, 0, CLSCTX_INPROC, IID_ICreateDevEnum, (void **) &devs); + checkError(prefixForMessage, hr); + if (devs && setupOutputSoundDevice(devs)) + { + devs->Release(); devs = 0; + std::string prefixForMessageSound; + { + std::stringstream ss; + ss << _imageStream.get() << " " << getSoundOutputDeviceName(); + prefixForMessageSound = ss.str(); + } + + IPin* soundOutputDevicePinIn = 0; + hr = _soundOutputDevice->FindPin(L"Audio Input pin (rendered)", &soundOutputDevicePinIn); + checkError(prefixForMessageSound, hr); + + hr = _graphBuilder->Connect(soundStreamPinOut, soundOutputDevicePinIn); + + if (soundOutputDevicePinIn) soundOutputDevicePinIn->Release(); soundOutputDevicePinIn = 0; + if (soundStreamPinOut) soundStreamPinOut->Release(); soundStreamPinOut = 0; + + if (!checkError(prefixForMessageSound, hr) && _soundOutputDevice) + { + _graphBuilder->RemoveFilter(_soundOutputDevice); + _soundOutputDevice->Release(); _soundOutputDevice = 0; + } + } + } + } + + return true; +} + + + +//----------------------------------------------------------------------------- +// CleanupDShow +//----------------------------------------------------------------------------- +void CTextureRenderer::releaseRessources() +{ + // Shut down the graph + if (_mediaControl) _mediaControl->Stop(); + _imageStream = 0; + + if (_mediaControl) _mediaControl->Release(); _mediaControl = 0; + if (_mediaEvent) _mediaEvent->Release(); _mediaEvent = 0; + if (_mediaSeeking) _mediaSeeking->Release(); _mediaSeeking = 0; + // remove filter outside because this is a filter too. +} + + +//----------------------------------------------------------------------------- +// CTextureRenderer constructor +//----------------------------------------------------------------------------- + +CTextureRenderer::CTextureRenderer( DirectShowImageStream* is, HRESULT* valid) + : CBaseVideoRenderer(__uuidof(CLSID_TextureRenderer), + NAME("Texture Renderer"), + NULL, + valid) +{ + std::string prefixForMessage; + { + std::stringstream ss; + ss << is; + prefixForMessage = ss.str(); + } + + if (FAILED(*valid)) + checkError(prefixForMessage, *valid); + + _imageStream = is; + _fileSource = 0; + _mediaControl = 0; + _mediaEvent = 0; + _mediaSeeking = 0; + _graphBuilder = 0; + _videoCaptureDevice = 0; + _soundOutputDevice = 0; + _soundCaptureDevice = 0; +} + + +//----------------------------------------------------------------------------- +// CTextureRenderer destructor +//----------------------------------------------------------------------------- +CTextureRenderer::~CTextureRenderer() +{ +} + + +//----------------------------------------------------------------------------- +// CheckMediaType: This method forces the graph to give us an R8G8B8 video +// type, making our copy to texture memory trivial. +//----------------------------------------------------------------------------- +HRESULT CTextureRenderer::CheckMediaType(const CMediaType *pmt) +{ + HRESULT hr = E_FAIL; + VIDEOINFO *pvi=0; + + CheckPointer(pmt,E_POINTER); + + // Reject the connection if this is not a video type + if( *pmt->FormatType() != FORMAT_VideoInfo ) { + return E_INVALIDARG; + } + + // Only accept RGB24 video + pvi = (VIDEOINFO *)pmt->Format(); + + if (!IsEqualGUID( *pmt->Type(), MEDIATYPE_Video)) + osg::notify(osg::WARN) << _imageStream.get() << " media type not a video format" << std::endl; + + + if( IsEqualGUID( *pmt->Subtype(), MEDIASUBTYPE_RGB24)) + { + osg::notify(osg::NOTICE) << _imageStream.get() << " Texture Renderer use media " << getStringFromGUID(pmt->Subtype()) << std::endl; + hr = S_OK; + } + else + { + osg::notify(osg::INFO) << _imageStream.get() << " Texture Renderer check media " << getStringFromGUID(pmt->Subtype()) << std::endl; + } + + return hr; +} + +//----------------------------------------------------------------------------- +// SetMediaType: Graph connection has been made. +//----------------------------------------------------------------------------- +HRESULT CTextureRenderer::SetMediaType(const CMediaType *pmt) +{ + // Retrive the size of this media type + VIDEOINFO *pviBmp; // Bitmap info header + pviBmp = (VIDEOINFO *)pmt->Format(); + + _width = pviBmp->bmiHeader.biWidth; + _height = abs(pviBmp->bmiHeader.biHeight); + _pitch = (_width * 3 + 3) & ~(3); // We are forcing RGB24 + _imageStream->setImage(_width, _height, 1, GL_RGB, GL_BGR, GL_UNSIGNED_BYTE, 0, osg::Image::NO_DELETE); + return S_OK; +} + +//----------------------------------------------------------------------------- +// DoRenderSample: A sample has been delivered. Copy it to the texture. +//----------------------------------------------------------------------------- +HRESULT CTextureRenderer::DoRenderSample( IMediaSample * pSample ) +{ + BYTE *pBmpBuffer; // Bitmap buffer, texture buffer + CheckPointer(pSample,E_POINTER); + + // Get the video bitmap buffer + pSample->GetPointer( &pBmpBuffer ); + if (_imageStream.valid()) + _imageStream->setImage(_width, _height, 1, GL_RGB, GL_BGR, GL_UNSIGNED_BYTE, pBmpBuffer, osg::Image::NO_DELETE); + return S_OK; +} + +void CTextureRenderer::syncStreams(bool state) +{ + if (state == true) + _dropFrame = !S_OK; + else + _dropFrame = S_OK; +} +HRESULT CTextureRenderer::ShouldDrawSampleNow(IMediaSample *sample, REFERENCE_TIME *start, REFERENCE_TIME *stop) { + return _dropFrame; // disable droping of frames +} + +bool CTextureRenderer::StopFilters() +{ + HRESULT hr; + if (_mediaControl) + { + hr = _mediaControl->Stop(); + if (FAILED(hr)) + { + osg::notify(osg::WARN) << _imageStream.get() << " " << getErrorMessage(hr) << std::endl; + return false; + } + } + return true; +} + +DirectShowImageStream::DirectShowImageStream() +{ + _options["captureWantedWidth"] = "1920"; + _options["captureWantedHeight"] = "1080"; + _options["captureWantedFps"] = "30"; + + HRESULT hr = CoInitialize (NULL); + if (FAILED(hr)) + { + osg::notify(osg::WARN) << this << " error in constructor " << getErrorMessage(hr) << std::endl; + } + +} +DirectShowImageStream::DirectShowImageStream(const DirectShowImageStream& d,const osg::CopyOp& c) : osg::ImageStream(d, c) +{ + // i guess it's invalid +} + +DirectShowImageStream::~DirectShowImageStream() +{ + stop(); + CoUninitialize(); +} + +bool DirectShowImageStream::openFile(const std::string& file) +{ + HRESULT valid = S_OK; + _renderer = new CTextureRenderer(this, &valid); + if (FAILED(valid)) + { + return false; + } + if (!_renderer->openFile(file)) + { + return false; + } + return true; +} + +bool DirectShowImageStream::openCaptureDevices() +{ + HRESULT valid = S_OK; + _renderer = new CTextureRenderer(this, &valid); + if (FAILED(valid)) + { + return false; + } + if (!_renderer->openCaptureDevices(_options)) + { + return false; + } + + return true; +} + + + +void DirectShowImageStream::play() +{ + OpenThreads::ScopedLock lock(_mutex); + if (_status == PLAYING) + return; + + if (_renderer.valid() && _renderer->_mediaControl) + { + HRESULT hr; + hr = _renderer->_mediaControl->Run(); + // Start the graph running; + if (FAILED(hr)) + { + osg::notify(osg::WARN) << this << " can't run the graph " << getErrorMessage(hr) << std::endl; + } + else + { + _status = PLAYING; + } + } +} + +void DirectShowImageStream::pause() +{ + OpenThreads::ScopedLock lock(_mutex); + if (_status == PAUSED) + return; + + if (_renderer.valid() && _renderer->_mediaControl) + { + HRESULT hr; + hr = _renderer->_mediaControl->Pause(); + if (FAILED(hr)) + { + osg::notify(osg::NOTICE) << this << " " << getErrorMessage(hr) << std::endl; + } + else + { + _status = PAUSED; + } + } +} + +void DirectShowImageStream::rewind() +{ + seek(0); +} + +osg::ImageStream::StreamStatus DirectShowImageStream::getStatus() +{ + OpenThreads::ScopedLock lock(_mutex); + return _status; +} + +void DirectShowImageStream::seek(double time) +{ + OpenThreads::ScopedLock lock(_mutex); + if (_renderer.valid() && _renderer->_mediaSeeking) + { + double start = time / (100 * 1e-9); + LONGLONG start2 = static_cast(start); + HRESULT hr = _renderer->_mediaSeeking->SetPositions(&start2,AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning); + if (FAILED(hr)) + { + osg::notify(osg::NOTICE) << this << " " << getErrorMessage(hr) << std::endl; + } + } + +} +void DirectShowImageStream::setOptions(const Options& map) +{ + for (Options::const_iterator it = map.begin(); it != map.end(); it++) + _options[it->first] = it->second; +} + +void DirectShowImageStream::quit(bool waitForThreadToExit) +{ + stop(); +} + +double DirectShowImageStream::getLength() const +{ + OpenThreads::ScopedLock lock(_mutex); + double duration = 0; + if (_renderer.valid() && _renderer->_mediaSeeking) + { + LONGLONG d = 0; + _renderer->_mediaSeeking->GetDuration(&d); + duration = static_cast(d); + duration = duration * (100.0 * 1e-9); // default unit in directshow IMediaSeeking + } + return duration; +} + +double DirectShowImageStream::getFrameRate() const +{ + OpenThreads::ScopedLock lock(_mutex); + int frameRate = 0; + if (_renderer.valid()) + _renderer->get_AvgFrameRate(&frameRate); + return static_cast(frameRate) * 1e-2; +} + +void DirectShowImageStream::setTimeMultiplier(double rate) +{ + OpenThreads::ScopedLock lock(_mutex); + if (_renderer.valid() && _renderer->_mediaSeeking) + _renderer->_mediaSeeking->SetRate(rate); +} + +double DirectShowImageStream::getTimeMultiplier() const +{ + OpenThreads::ScopedLock lock(_mutex); + double rate = 1.0; + if (_renderer.valid() && _renderer->_mediaSeeking) + _renderer->_mediaSeeking->GetRate(&rate); + return rate; +} + +void DirectShowImageStream::stop() +{ + OpenThreads::ScopedLock lock(_mutex); + if (!_renderer.valid()) + return; + if (!_renderer->StopFilters()) + osg::notify(osg::WARN) << this << " cant stop filters" << std::endl; + + _renderer->releaseRessources(); + // Enumerate the filters in the graph. + IEnumFilters *pEnum = NULL; + IGraphBuilder* gb = _renderer->getGraphBuilder(); + if (!gb) + return; + HRESULT hr = gb->EnumFilters(&pEnum); + if (SUCCEEDED(hr)) + { + IBaseFilter *pFilter = NULL; + while (S_OK == pEnum->Next(1, &pFilter, NULL)) + { + // Remove the filter. + gb->RemoveFilter(pFilter); + // Reset the enumerator. + pEnum->Reset(); + pFilter->Release(); + } + pEnum->Release(); + } + if (gb) gb->Release(); gb = 0; + _renderer = 0; +} diff --git a/src/osgPlugins/directshow/ReaderWriterDirectShow.cpp b/src/osgPlugins/directshow/ReaderWriterDirectShow.cpp new file mode 100644 index 000000000..605d82791 --- /dev/null +++ b/src/osgPlugins/directshow/ReaderWriterDirectShow.cpp @@ -0,0 +1,94 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 2009 Tharsis Software + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library 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 + * OpenSceneGraph Public License for more details. + * + * Authors: + * Cedric Pinson +*/ + + +#include +#include +#include + +#include "DirectShowTexture" + + +class ReaderWriterDirectShow : public osgDB::ReaderWriter +{ +public: + + ReaderWriterDirectShow() + { + } + + virtual ~ReaderWriterDirectShow() + { + } + + virtual const char * className() const + { + return "ReaderWriterDirectShow"; + } + + virtual ReadResult readImage(const std::string & filename, const osgDB::ReaderWriter::Options * options) const + { + const std::string ext = osgDB::getLowerCaseFileExtension(filename); + if (ext=="directshow") return readImage(osgDB::getNameLessExtension(filename),options); + return readImageStream(filename, options); + } + + ReadResult readImageStream(const std::string& filename, const osgDB::ReaderWriter::Options * options) const + { + osg::notify(osg::INFO) << "ReaderWriterFFmpeg::readImage " << filename << std::endl; + const std::string path = osgDB::containsServerAddress(filename) ? + filename : + osgDB::findDataFile(filename, options); + + osg::ref_ptr image_stream(new DirectShowImageStream); + + if (path.empty()) // try with capture + { + std::map map; + if (options) + { + map["captureWantedWidth"] = options->getPluginStringData("captureWantedWidth"); + map["captureWantedHeight"] = options->getPluginStringData("captureWantedHeight"); + map["captureWantedFps"] = options->getPluginStringData("captureWantedFps"); + map["captureVideoDevice"] = options->getPluginStringData("captureVideoDevice"); + map["captureSoundDevice"] = options->getPluginStringData("captureSoundDevice"); + map["captureSoundDeviceNbChannels"] = options->getPluginStringData("captureSoundDeviceNbChannels"); + } + if (filename != "capture") + { + if (!options || (options && options->getPluginStringData("captureVideoDevice").empty())) + map["captureVideoDevice"] = filename; + } + image_stream->setOptions(map); + + if (! image_stream->openCaptureDevices()) + return ReadResult::FILE_NOT_HANDLED; + return image_stream.release(); + } + + if (! image_stream->openFile(filename)) + return ReadResult::FILE_NOT_HANDLED; + + return image_stream.release(); + } + +private: + +}; + + + +REGISTER_OSGPLUGIN(directshow, ReaderWriterDirectShow)