Files
OpenSceneGraph/src/osgPlugins/directshow/DirectShowTexture.cpp
Robert Osfield 7552954ef3 From Cedric Pinson, "Here an update of the directshow plugin. It fixes issues with
synchronization, improve capture device support.

here how to use it to display a capture device:

osg::Options* options = new osg::Options;
options->setPluginStringData("captureWantedWidth", "800");
options->setPluginStringData("captureWantedHeight", "600");
options->setPluginStringData("captureWantedFps", "30");
options->setPluginStringData("captureVideoDevice", "USB Video Device" );
options->setPluginStringData("captureSoundDevice", "");
then
osgDB::readImageFile("capture.directshow", options)
you can use a graphedit application to list devices available in
directshow.


for classic avi file you just need to do a
osgDB::readImageFile("file.avi.directshow");
You will need of course to install the codec needed by directshow to
read the avi files.

I recommand this tool http://avicodec.duby.info/, that check which
video/sound codec is needed to play an avi file.


You can test it with the osgmovie example.
"
2009-11-20 10:48:51 +00:00

1873 lines
71 KiB
C++

/* -*-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 <cedric.pinson@plopbyte.net>
*/
#include "DirectShowTexture"
#include <osg/notify>
#include <osgDB/WriteFile>
#include <sstream>
#include <windows.h>
#include <mmsystem.h>
#include <comdef.h>
#include <strsafe.h>
#include <functional>
#include <locale>
#include <string>
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")},
{&AMPROPSETID_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<DeviceEntry> _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<AM_MEDIA_TYPE*, VIDEOINFOHEADER *> CapEntry;
std::vector<CapEntry> _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<AM_MEDIA_TYPE*, VIDEOINFOHEADER *> getCaps(int width, int height, double fps)
{
std::vector<CapEntry> 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<double, CapEntry> 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<double, CapEntry>(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<VIDEOINFOHEADER*>(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<void**>(&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; index<count; ++index)
{
hr = pISC->GetStreamCaps(index, &pmt, reinterpret_cast<BYTE*>(&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<OpenThreads::Mutex> 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<OpenThreads::Mutex> 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<OpenThreads::Mutex> lock(_mutex);
return _status;
}
void DirectShowImageStream::seek(double time)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
if (_renderer.valid() && _renderer->_mediaSeeking)
{
double start = time / (100 * 1e-9);
LONGLONG start2 = static_cast<LONGLONG>(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<OpenThreads::Mutex> lock(_mutex);
double duration = 0;
if (_renderer.valid() && _renderer->_mediaSeeking)
{
LONGLONG d = 0;
_renderer->_mediaSeeking->GetDuration(&d);
duration = static_cast<double>(d);
duration = duration * (100.0 * 1e-9); // default unit in directshow IMediaSeeking
}
return duration;
}
double DirectShowImageStream::getFrameRate() const
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
int frameRate = 0;
if (_renderer.valid())
_renderer->get_AvgFrameRate(&frameRate);
return static_cast<double>(frameRate) * 1e-2;
}
void DirectShowImageStream::setTimeMultiplier(double rate)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
if (_renderer.valid() && _renderer->_mediaSeeking)
_renderer->_mediaSeeking->SetRate(rate);
}
double DirectShowImageStream::getTimeMultiplier() const
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
double rate = 1.0;
if (_renderer.valid() && _renderer->_mediaSeeking)
_renderer->_mediaSeeking->GetRate(&rate);
return rate;
}
void DirectShowImageStream::stop()
{
OpenThreads::ScopedLock<OpenThreads::Mutex> 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;
}